Changeset 2694 for sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments-network/includes/wordcamp-budgets-dashboard.php
- Timestamp:
- 03/04/2016 10:34:58 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordcamp.org/public_html/wp-content/plugins/wordcamp-payments-network/includes/wordcamp-budgets-dashboard.php
r2535 r2694 8 8 */ 9 9 10 add_action( 'network_admin_menu', __NAMESPACE__ . '\register_budgets_menu' ); 11 add_action( 'network_admin_menu', __NAMESPACE__ . '\remove_budgets_submenu', 11 ); // after other modules have registered their submenu pages 12 add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\enqueue_scripts' ); 10 add_action( 'network_admin_menu', __NAMESPACE__ . '\register_budgets_menu' ); 11 add_action( 'network_admin_menu', __NAMESPACE__ . '\remove_budgets_submenu', 11 ); // after other modules have registered their submenu pages 12 add_action( 'network_admin_menu', __NAMESPACE__ . '\import_export_admin_menu', 11 ); 13 add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\enqueue_scripts', 10, 1 ); 14 15 add_action( 'admin_init', __NAMESPACE__ . '\process_export_request' ); 13 16 14 17 /** … … 32 35 33 36 /** 37 * Register the Import/Export dashboard menu item. 38 */ 39 function import_export_admin_menu() { 40 add_submenu_page( 41 'wordcamp-budgets-dashboard', 42 'WordCamp Budgets Import/Export', 43 'Import/Export', 44 'manage_network', 45 'wcb-import-export', 46 __NAMESPACE__ . '\render_import_export' 47 ); 48 } 49 50 /** 51 * Render the import/export screen. 52 */ 53 function render_import_export() { 54 $current_tab = 'import'; 55 if ( ! empty( $_GET['section'] ) && in_array( $_GET['section'], array( 'import', 'export' ) ) ) { 56 $current_tab = $_GET['section']; 57 } 58 59 ?> 60 <div class="wrap"> 61 <h1>Import/Export</h1> 62 63 <?php do_action( 'admin_notices' ); ?> 64 <?php settings_errors(); ?> 65 66 <h3 class="nav-tab-wrapper"> 67 <a class="nav-tab <?php if ( $current_tab == 'import' ) { echo 'nav-tab-active'; } ?>" 68 href="<?php echo add_query_arg( array( 69 'page' => 'wcb-import-export', 70 'section' => 'import', 71 ), network_admin_url( 'admin.php' ) ); ?>">Import</a> 72 73 <a class="nav-tab <?php if ( $current_tab == 'export' ) { echo 'nav-tab-active'; } ?>" 74 href="<?php echo add_query_arg( array( 75 'page' => 'wcb-import-export', 76 'section' => 'export', 77 ), network_admin_url( 'admin.php' ) ); ?>">Export</a> 78 </h3> 79 80 <?php 81 if ( 'export' == $current_tab ) { 82 render_export_tab(); 83 } elseif ( 'import' == $current_tab ) { 84 render_import_tab(); 85 } 86 ?> 87 88 </div> <!-- /wrap --> 89 <?php 90 } 91 92 /** 93 * Get available export options. 94 * 95 * @return array 96 */ 97 function get_export_types() { 98 return array( 99 'default' => array( 100 'label' => 'Regular CSV', 101 'mime_type' => 'text/csv', 102 'callback' => __NAMESPACE__ . '\_generate_payment_report_default', 103 'filename' => 'wordcamp-payments-%s-%s-default.csv', 104 ), 105 'jpm_wires' => array( 106 'label' => 'JP Morgan Access - Wire Payments', 107 'mime_type' => 'text/csv', 108 'callback' => __NAMESPACE__ . '\_generate_payment_report_jpm_wires', 109 'filename' => 'wordcamp-payments-%s-%s-jpm-wires.csv', 110 ), 111 'jpm_ach' => array( 112 'label' => 'JP Morgan - NACHA', 113 'mime_type' => 'text/plain', 114 'callback' => __NAMESPACE__ . '\_generate_payment_report_jpm_ach', 115 'filename' => 'wordcamp-payments-%s-%s-jpm-ach.ach', 116 ), 117 'jpm_checks' => array( 118 'label' => 'JP Morgan - Quick Checks', 119 'mime_type' => 'text/csv', 120 'callback' => __NAMESPACE__ . '\_generate_payment_report_jpm_checks', 121 'filename' => 'wordcamp-payments-%s-%s-jpm-checks.csv', 122 ), 123 ); 124 } 125 126 /** 127 * Render the Import tab 128 */ 129 function render_import_tab() { 130 echo '<p>Move along, nothing to see here.</p>'; 131 } 132 133 /** 134 * Render the export tab 135 */ 136 function render_export_tab() { 137 $today = date( 'Y-m-d' ); 138 $last_month = date( 'Y-m-d', strtotime( 'now - 1 month' ) ); 139 ?> 140 <script> 141 /** 142 * Fallback to the jQueryUI datepicker if the browser doesn't support <input type="date"> 143 */ 144 jQuery( document ).ready( function( $ ) { 145 var browserTest = document.createElement( 'input' ); 146 browserTest.setAttribute( 'type', 'date' ); 147 148 if ( 'text' === browserTest.type ) { 149 $( '#wcpn_export' ).find( 'input[type=date]' ).datepicker( { 150 dateFormat : 'yy-mm-dd', 151 changeMonth: true, 152 changeYear : true 153 } ); 154 } 155 } ); 156 </script> 157 158 <form id="wcpn_export" method="POST"> 159 <?php wp_nonce_field( 'export', 'wcb-request-export' ); ?> 160 161 <h2>Export Settings</h2> 162 163 <table class="form-table"> 164 <tr> 165 <th>Types</th> 166 <td> 167 <label><input type="checkbox" name="wcb-export-types-vendor-payments" 168 value="1" checked disabled /> Vendor Payments</label><br /> 169 <label><input type="checkbox" name="wcb-export-types-reimbursements" 170 value="1" disabled /> Reimbursements</label> 171 </td> 172 <tr> 173 <th>Status</th> 174 <td> 175 <select name="wcb-export-status"> 176 <option value="wcb-approved"><?php _e( 'Approved', 'wordcamporg' ); ?></option> 177 <option value="wcb-paid"><?php _e( 'Paid', 'wordcamporg' ); ?></option> 178 </select> 179 </td> 180 </tr> 181 <tr> 182 <th>Date Range</th> 183 <td> 184 <input type="date" name="wcb-export-start-date" 185 class="medium-text" value="<?php echo esc_attr( $last_month ); ?>" /> to 186 <input type="date" name="wcb-export-end-date" 187 class="medium-text" value="<?php echo esc_attr( $today ); ?>" /> 188 </td> 189 </tr> 190 <tr> 191 <th>Format</th> 192 <td> 193 <select name="wcb-export-type"> 194 <?php foreach ( get_export_types() as $key => $export_type ) : ?> 195 <option value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $export_type['label'] ); ?></option> 196 <?php endforeach; ?> 197 </select> 198 </td> 199 </tr> 200 </table> 201 202 <?php submit_button( 'Download Export' ); ?> 203 </form> 204 <?php 205 } 206 207 /** 208 * Process export requests 209 */ 210 function process_export_request() { 211 if ( empty( $_GET['page'] ) || $_GET['page'] != 'wcb-import-export' ) 212 return; 213 214 if ( empty( $_GET['section'] ) || $_GET['section'] != 'export' ) 215 return; 216 217 if ( empty( $_POST['wcb-request-export'] ) ) 218 return; 219 220 if ( ! current_user_can( 'manage_network' ) || ! check_admin_referer( 'export', 'wcb-request-export' ) ) 221 return; 222 223 $export_types = get_export_types(); 224 225 if ( array_key_exists( $_POST['wcb-export-type'], $export_types ) ) { 226 $export_type = $export_types[ $_POST['wcb-export-type'] ]; 227 } else { 228 $export_type = $export_types['default']; 229 } 230 231 $status = $_POST['wcb-export-status']; 232 if ( ! in_array( $status, array( 'wcb-approved', 'wcb-paid' ) ) ) 233 $status = 'wcb-approved'; 234 235 $start_date = strtotime( $_POST['wcb-export-start-date'] . ' 00:00:00' ); 236 $end_date = strtotime( $_POST['wcb-export-end-date'] . ' 23:59:59' ); 237 $filename = sprintf( $export_type['filename'], date( 'Ymd', $start_date ), date( 'Ymd', $end_date ) ); 238 $filename = sanitize_file_name( $filename ); 239 240 $report = generate_payment_report( array( 241 'status' => $status, 242 'start_date' => $start_date, 243 'end_date' => $end_date, 244 'export_type' => $export_type, 245 ) ); 246 247 if ( is_wp_error( $report ) ) { 248 add_settings_error( 'wcb-dashboard', $report->get_error_code(), $report->get_error_message() ); 249 } else { 250 header( sprintf( 'Content-Type: %s', $export_type['mime_type'] ) ); 251 header( sprintf( 'Content-Disposition: attachment; filename="%s"', $filename ) ); 252 header( 'Cache-control: private' ); 253 header( 'Pragma: private' ); 254 header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' ); 255 256 echo $report; 257 die(); 258 } 259 } 260 261 /* 262 * Generate and return the raw payment report contents 263 * 264 * @param array $args 265 * 266 * @return string | WP_Error 267 */ 268 function generate_payment_report( $args ) { 269 global $wpdb; 270 271 $args = wp_parse_args( $args, array( 272 'status' => '', 273 'start_date' => '', 274 'end_date' => '', 275 'export_type' => '', 276 ) ); 277 278 if ( ! is_int( $args['start_date'] ) || ! is_int( $args['end_date'] ) ) { 279 return new WP_Error( 'wcb-bad-dates', 'Invalid start or end date.' ); 280 } 281 282 // todo: support other index tables. 283 $table_name = $wpdb->get_blog_prefix(0) . 'wordcamp_payments_index'; 284 $date_type = 'updated'; 285 286 if ( $args['status'] == 'wcb-paid' ) 287 $date_type = 'paid'; 288 289 $request_indexes = $wpdb->get_results( $wpdb->prepare( " 290 SELECT * 291 FROM `{$table_name}` 292 WHERE `{$date_type}` BETWEEN %d AND %d", 293 $args['start_date'], 294 $args['end_date'] 295 ) ); 296 297 if ( ! is_callable( $args['export_type']['callback'] ) ) 298 return new \WP_Error( 'wcb-invalid-type', 'The export type is invalid.' ); 299 300 $args['request_indexes'] = $request_indexes; 301 302 return call_user_func( $args['export_type']['callback'], $args ); 303 } 304 305 /** 306 * Default CSV report 307 * 308 * @param array $args 309 * 310 * @return string 311 */ 312 function _generate_payment_report_default( $args ) { 313 $args = wp_parse_args( $args, array( 314 'request_indexes' => array(), 315 'status' => '', 316 ) ); 317 318 $column_headings = array( 319 'WordCamp', 'ID', 'Title', 'Status', 'Date Vendor was Paid', 'Creation Date', 'Due Date', 'Amount', 320 'Currency', 'Category', 'Payment Method','Vendor Name', 'Vendor Contact Person', 'Vendor Country', 321 'Check Payable To', 'URL', 'Supporting Documentation Notes', 322 ); 323 324 ob_start(); 325 $report = fopen( 'php://output', 'w' ); 326 327 fputcsv( $report, $column_headings ); 328 329 foreach( $args['request_indexes'] as $index ) { 330 switch_to_blog( $index->blog_id ); 331 332 $request = get_post( $index->post_id ); 333 334 $back_compat_statuses = array( 335 'unpaid' => 'draft', 336 'incomplete' => 'wcb-incomplete', 337 'paid' => 'wcb-paid', 338 ); 339 340 // Map old statuses to new statuses. 341 if ( array_key_exists( $request->post_status, $back_compat_statuses ) ) { 342 $request->post_status = $back_compat_statuses[ $request->post_status ]; 343 } 344 345 if ( $args['status'] && $request->post_status != $args['status'] ) { 346 restore_current_blog(); 347 continue; 348 } 349 350 $currency = get_post_meta( $index->post_id, '_camppayments_currency', true ); 351 $category = get_post_meta( $index->post_id, '_camppayments_payment_category', true ); 352 $date_vendor_paid = get_post_meta( $index->post_id, '_camppayments_date_vendor_paid', true ); 353 354 if ( $date_vendor_paid ) { 355 $date_vendor_paid = date( 'Y-m-d', $date_vendor_paid ); 356 } 357 358 if ( 'null-select-one' === $currency ) { 359 $currency = ''; 360 } 361 362 if ( 'null' === $category ) { 363 $category = ''; 364 } 365 366 $row = array( 367 get_wordcamp_name(), 368 sprintf( '%d-%d', $index->blog_id, $index->post_id ), 369 html_entity_decode( $request->post_title ), 370 $index->status, 371 $date_vendor_paid, 372 date( 'Y-m-d', $index->created ), 373 date( 'Y-m-d', $index->due ), 374 get_post_meta( $index->post_id, '_camppayments_payment_amount', true ), 375 $currency, 376 $category, 377 get_post_meta( $index->post_id, '_camppayments_payment_method', true ), 378 get_post_meta( $index->post_id, '_camppayments_vendor_name', true ), 379 get_post_meta( $index->post_id, '_camppayments_vendor_contact_person', true ), 380 get_post_meta( $index->post_id, '_camppayments_vendor_country', true ), 381 \WCP_Encryption::maybe_decrypt( get_post_meta( $index->post_id, '_camppayments_payable_to', true ) ), 382 get_edit_post_link( $index->post_id ), 383 get_post_meta( $index->post_id, '_camppayments_file_notes', true ), 384 ); 385 386 restore_current_blog(); 387 388 if ( ! empty( $row ) ) { 389 fputcsv( $report, $row ); 390 } 391 } 392 393 fclose( $report ); 394 return ob_get_clean(); 395 } 396 397 /** 398 * Quick Checks via JP Morgan 399 * 400 * @param array $args 401 * 402 * @return string 403 */ 404 function _generate_payment_report_jpm_checks( $args ) { 405 $args = wp_parse_args( $args, array( 406 'request_indexes' => array(), 407 'status' => '', 408 ) ); 409 410 $options = apply_filters( 'wcb_payment_req_check_options', array( 411 'pws_customer_id' => '', 412 'account_number' => '', 413 'contact_email' => '', 414 'contact_phone' => '', 415 ) ); 416 417 $report = fopen( 'php://output', 'w' ); 418 ob_start(); 419 420 // File Header 421 fputcsv( $report, array( 'FILHDR', 'PWS', $options['pws_customer_id'], date( 'm/d/Y' ), date( 'Hi' ) ), ',', '|' ); 422 423 $total = 0; 424 $count = 0; 425 426 if ( false !== get_site_transient( '_wcb_jpm_checks_counter_lock' ) ) { 427 wp_die( 'JPM Checks Export is locked. Please try again later or contact support.' ); 428 } 429 430 // Avoid at least *some* race conditions. 431 set_site_transient( '_wcb_jpm_checks_counter_lock', 1, 30 ); 432 $start = absint( get_site_option( '_wcb_jpm_checks_counter', 0 ) ); 433 434 foreach ( $args['request_indexes'] as $index ) { 435 switch_to_blog( $index->blog_id ); 436 $post = get_post( $index->post_id ); 437 438 if ( $args['status'] && $post->post_status != $args['status'] ) { 439 restore_current_blog(); 440 continue; 441 } 442 443 if ( get_post_meta( $post->ID, '_camppayments_payment_method', true ) != 'Check' ) { 444 restore_current_blog(); 445 continue; 446 } 447 448 $count++; 449 $amount = round( floatval( get_post_meta( $post->ID, '_camppayments_payment_amount', true ) ), 2 ); 450 $total += $amount; 451 452 $payable_to = \WCP_Encryption::maybe_decrypt( get_post_meta( $post->ID, '_camppayments_payable_to', true ) ); 453 $payable_to = html_entity_decode( $payable_to ); // J&J to J&J 454 $countries = \WordCamp_Budgets::get_valid_countries_iso3166(); 455 $vendor_country_code = get_post_meta( $post->ID, '_camppayments_vendor_country_iso3166', true ); 456 if ( ! empty( $countries[ $vendor_country_code ] ) ) { 457 $vendor_country_code = $countries[ $vendor_country_code ]['alpha3']; 458 } 459 460 $description = sanitize_text_field( get_post_meta( $post->ID, '_camppayments_description', true ) ); 461 $description = html_entity_decode( $description ); 462 $invoice_number = get_post_meta( $post->ID, '_camppayments_invoice_number', true ); 463 if ( ! empty( $invoice_number ) ) { 464 $description = sprintf( 'Invoice %s. %s', $invoice_number, $description ); 465 } 466 467 // Payment Header 468 fputcsv( $report, array( 469 'PMTHDR', 470 'USPS', 471 'QKCHECKS', 472 date( 'm/d/Y' ), 473 number_format( $amount, 2, '.', '' ), 474 $options['account_number'], 475 $start + $count, // must be globally unique? 476 $options['contact_email'], 477 $options['contact_phone'], 478 ), ',', '|' ); 479 480 // Payee Name Record 481 fputcsv( $report, array( 482 'PAYENM', 483 substr( $payable_to, 0, 35 ), 484 '', 485 sprintf( '%d-%d', $index->blog_id, $index->post_id ), 486 ), ',', '|' ); 487 488 // Payee Address Record 489 fputcsv( $report, array( 490 'PYEADD', 491 substr( get_post_meta( $post->ID, '_camppayments_vendor_street_address', true ), 0, 35 ), 492 '', 493 ), ',', '|' ); 494 495 // Additional Payee Address Record 496 fputcsv( $report, array( 'ADDPYE', '', '' ), ',', '|' ); 497 498 // Payee Postal Record 499 fputcsv( $report, array( 500 'PYEPOS', 501 substr( get_post_meta( $post->ID, '_camppayments_vendor_city', true ), 0, 35 ), 502 substr( get_post_meta( $post->ID, '_camppayments_vendor_state', true ), 0, 35 ), 503 substr( get_post_meta( $post->ID, '_camppayments_vendor_zip_code', true ), 0, 10 ), 504 substr( $vendor_country_code, 0, 3 ), 505 ), ',', '|' ); 506 507 // Payment Description 508 fputcsv( $report, array( 509 'PYTDES', 510 substr( $description, 0, 122 ), 511 ), ',', '|' ); 512 513 restore_current_blog(); 514 } 515 516 // File Trailer 517 fputcsv( $report, array( 'FILTRL', $count * 6 + 2 ), ',', '|' ); 518 519 // Update counter and unlock 520 $start = absint( get_site_option( '_wcb_jpm_checks_counter', 0 ) ); 521 update_site_option( '_wcb_jpm_checks_counter', $start + $count ); 522 delete_site_transient( '_wcb_jpm_checks_counter_lock' ); 523 524 fclose( $report ); 525 return ob_get_clean(); 526 } 527 528 /** 529 * NACHA via JP Morgan 530 * 531 * @param array $args 532 * 533 * @return string 534 */ 535 function _generate_payment_report_jpm_ach( $args ) { 536 $args = wp_parse_args( $args, array( 537 'request_indexes' => array(), 538 'status' => '', 539 ) ); 540 541 $ach_options = apply_filters( 'wcb_payment_req_ach_options', array( 542 'bank-routing-number' => '', // Immediate Destination (bank routing number) 543 'company-id' => '', // Company ID 544 'financial-inst' => '', // Originating Financial Institution 545 ) ); 546 547 ob_start(); 548 549 // File Header Record 550 551 echo '1'; // Record Type Code 552 echo '01'; // Priority Code 553 echo ' ' . str_pad( substr( $ach_options['bank-routing-number'], 0, 9 ), 9, '0', STR_PAD_LEFT ); 554 echo str_pad( substr( $ach_options['company-id'], 0, 10 ), 10, '0', STR_PAD_LEFT ); // Immediate Origin (TIN) 555 echo date( 'ymd' ); // Transmission Date 556 echo date( 'Hi' ); // Transmission Time 557 echo 'A'; // File ID Modifier 558 echo '094'; // Record Size 559 echo '10'; // Blocking Factor 560 echo '1'; // Format Code 561 echo str_pad( 'JPMORGANCHASE', 23 ); // Destination 562 echo str_pad( 'WCEXPORT', 23 ); // Origin 563 echo str_pad( '', 8 ); // Reference Code (optional) 564 echo PHP_EOL; 565 566 // Batch Header Record 567 568 echo '5'; // Record Type Code 569 echo '200'; // Service Type Code 570 echo 'WordCamp Communi'; // Company Name 571 echo str_pad( '', 20 ); // Blanks 572 echo str_pad( substr( $ach_options['company-id'], 0, 10 ), 10 ); // Company Identification 573 574 // Get the first one in the set. 575 // @todo Split batches by account type. 576 foreach ( $args['request_indexes'] as $index ) { 577 switch_to_blog( $index->blog_id ); 578 $post = get_post( $index->post_id ); 579 $account_type = get_post_meta( $post->ID, '_camppayments_ach_account_type', true ); 580 restore_current_blog(); 581 582 break; 583 } 584 585 $entry_class = $account_type == 'Personal' ? 'PPD' : 'CCD'; 586 echo $entry_class; // Standard Entry Class 587 588 echo 'Vendor Pay'; // Entry Description 589 echo date( 'ymd', _next_business_day_timestamp() ); // Company Description Date 590 echo date( 'ymd', _next_business_day_timestamp() ); // Effective Entry Date 591 echo str_pad( '', 3 ); // Blanks 592 echo '1'; // Originator Status Code 593 echo str_pad( substr( $ach_options['financial-inst'], 0, 8 ), 8 ); // Originating Financial Institution 594 echo '0000001'; // Batch Number 595 echo PHP_EOL; 596 597 $count = 0; 598 $total = 0; 599 $hash = 0; 600 601 foreach ( $args['request_indexes'] as $index ) { 602 switch_to_blog( $index->blog_id ); 603 $post = get_post( $index->post_id ); 604 605 if ( $args['status'] && $post->post_status != $args['status'] ) { 606 restore_current_blog(); 607 continue; 608 } 609 610 if ( get_post_meta( $post->ID, '_camppayments_payment_method', true ) != 'Direct Deposit' ) { 611 restore_current_blog(); 612 continue; 613 } 614 615 $count++; 616 617 // Entry Detail Record 618 619 echo '6'; // Record Type Code 620 621 $transaction_code = $account_type == 'Personal' ? '27' : '22'; 622 echo $transaction_code; // Transaction Code 623 624 // Transit/Routing Number of Destination Bank + Check digit 625 $routing_number = get_post_meta( $post->ID, '_camppayments_ach_routing_number', true ); 626 $routing_number = \WCP_Encryption::maybe_decrypt( $routing_number ); 627 $routing_number = substr( $routing_number, 0, 8 + 1 ); 628 $routing_number = str_pad( $routing_number, 8 + 1 ); 629 $hash += absint( substr( $routing_number, 0, 8 ) ); 630 echo $routing_number; 631 632 // Bank Account Number 633 $account_number = get_post_meta( $post->ID, '_camppayments_ach_account_number', true ); 634 $account_number = \WCP_Encryption::maybe_decrypt( $account_number ); 635 $account_number = substr( $account_number, 0, 17 ); 636 $account_number = str_pad( $account_number, 17 ); 637 echo $account_number; 638 639 // Amount 640 $amount = round( floatval( get_post_meta( $post->ID, '_camppayments_payment_amount', true ) ), 2 ); 641 $total += $amount; 642 $amount = str_pad( number_format( $amount, 2, '', '' ), 10, '0', STR_PAD_LEFT ); 643 echo $amount; 644 645 // Individual Identification Number 646 echo str_pad( sprintf( '%d-%d', $index->blog_id, $index->post_id ), 15 ); 647 648 // Individual Name 649 $name = get_post_meta( $post->ID, '_camppayments_ach_account_holder_name', true ); 650 $name = \WCP_Encryption::maybe_decrypt( $name ); 651 $name = substr( $name, 0, 22 ); 652 $name = str_pad( $name, 22 ); 653 echo $name; 654 655 echo ' '; // User Defined Data 656 echo '0'; // Addenda Record Indicator 657 658 // Trace Number 659 echo str_pad( substr( $ach_options['bank-routing-number'], 0, 8 ), 8, '0', STR_PAD_LEFT ); // routing number 660 echo str_pad( $count, 7, '0', STR_PAD_LEFT ); // sequence number 661 echo PHP_EOL; 662 } 663 664 // Batch Trailer Record 665 666 echo '8'; // Record Type Code 667 echo '200'; // Service Class Code 668 echo str_pad( $count, 6, '0', STR_PAD_LEFT ); // Entry/Addenda Count 669 echo str_pad( substr( $hash, -10 ), 10, '0', STR_PAD_LEFT ); // Entry Hash 670 echo str_pad( number_format( $total, 2, '', '' ), 12, '0', STR_PAD_LEFT ); // Total Debit Entry Dollar Amount 671 echo str_pad( 0, 12, '0', STR_PAD_LEFT ); // Total Credit Entry Dollar Amount 672 echo str_pad( substr( $ach_options['company-id'], 0, 10 ), 10 ); // Company ID 673 echo str_pad( '', 25 ); // Blanks 674 echo str_pad( substr( $ach_options['financial-inst'], 0, 8 ), 8 ); // Originating Financial Institution 675 echo '0000001'; // Batch Number 676 echo PHP_EOL; 677 678 679 // File Trailer Record 680 681 echo '9'; // Record Type Code 682 echo '000001'; // Batch Count 683 echo str_pad( ceil( $count / 10 ), 6, '0', STR_PAD_LEFT ); // Block Count 684 echo str_pad( $count, 8, '0', STR_PAD_LEFT ); // Entry/Addenda Count 685 echo str_pad( substr( $hash, -10 ), 10, '0', STR_PAD_LEFT ); // Entry Hash 686 echo str_pad( number_format( $total, 2, '', '' ), 12, '0', STR_PAD_LEFT ); // Total Debit Entry Dollar Amount 687 echo str_pad( 0, 12, '0', STR_PAD_LEFT ); // Total Credit Entry Dollar Amount 688 echo str_pad( '', 39 ); // Blanks 689 echo PHP_EOL; 690 691 // The file must have a number of lines that is a multiple of 10 (e.g. 10, 20, 30). 692 echo str_repeat( PHP_EOL, 10 - ( ( 4 + $count ) % 10 ) - 1 ); 693 return ob_get_clean(); 694 } 695 696 /** 697 * Wires via JP Morgan 698 * 699 * @param array $args 700 * 701 * @return string 702 */ 703 function _generate_payment_report_jpm_wires( $args ) { 704 $args = wp_parse_args( $args, array( 705 'request_indexes' => array(), 706 'status' => '', 707 ) ); 708 709 ob_start(); 710 $report = fopen( 'php://output', 'w' ); 711 712 // JPM Header 713 fputcsv( $report, array( 'HEADER', gmdate( 'YmdHis' ), '1' ) ); 714 715 $total = 0; 716 $count = 0; 717 718 foreach ( $args['request_indexes'] as $index ) { 719 switch_to_blog( $index->blog_id ); 720 $post = get_post( $index->post_id ); 721 722 if ( $args['status'] && $post->post_status != $args['status'] ) { 723 restore_current_blog(); 724 continue; 725 } 726 727 // Only wires here. 728 if ( get_post_meta( $post->ID, '_camppayments_payment_method', true ) != 'Wire' ) { 729 restore_current_blog(); 730 continue; 731 } 732 733 $amount = round( floatval( get_post_meta( $post->ID, '_camppayments_payment_amount', true ) ), 2); 734 $total += $amount; 735 $count += 1; 736 737 // If account starts with two letters, it's most likely an IBAN 738 $account = get_post_meta( $post->ID, '_camppayments_beneficiary_account_number', true ); 739 $account = \WCP_Encryption::maybe_decrypt( $account ); 740 $account = preg_replace( '#\s#','', $account ); 741 $account_type = preg_match( '#^[a-z]{2}#i', $account ) ? 'IBAN' : 'ACCT'; 742 743 $row = array( 744 '1-input-type' => 'P', 745 '2-payment-method' => 'WIRES', 746 '3-debit-bank-id' => apply_filters( 'wcb_payment_req_bank_id', '' ), // external file 747 '4-account-number' => apply_filters( 'wcb_payment_req_bank_number', '' ), // external file 748 '5-bank-to-bank' => 'N', 749 '6-txn-currency' => get_post_meta( $post->ID, '_camppayments_currency', true ), 750 '7-txn-amount' => number_format( $amount, 2, '.', '' ), 751 '8-equiv-amount' => '', 752 '9-clearing' => '', 753 '10-ben-residence' => '', 754 '11-rate-type' => '', 755 '12-blank' => '', 756 '13-value-date' => '', 757 758 '14-id-type' => $account_type, 759 '15-id-value' => $account, 760 '16-ben-name' => substr( \WCP_Encryption::maybe_decrypt( 761 get_post_meta( $post->ID, '_camppayments_beneficiary_name', true ) ), 0, 35 ), 762 '17-address-1' => substr( \WCP_Encryption::maybe_decrypt( 763 get_post_meta( $post->ID, '_camppayments_beneficiary_street_address', true ) ), 0, 35 ), 764 '18-address-2' => '', 765 '19-city-state-zip' => substr( sprintf( '%s %s %s', 766 \WCP_Encryption::maybe_decrypt( get_post_meta( $post->ID, '_camppayments_beneficiary_city', true ) ), 767 \WCP_Encryption::maybe_decrypt( get_post_meta( $post->ID, '_camppayments_beneficiary_state', true ) ), 768 \WCP_Encryption::maybe_decrypt( get_post_meta( $post->ID, '_camppayments_beneficiary_zip_code', true ) ) 769 ), 0, 32 ), 770 '20-blank' => '', 771 '21-country' => \WCP_Encryption::maybe_decrypt( 772 get_post_meta( $post->ID, '_camppayments_beneficiary_country_iso3166', true ) ), 773 '22-blank' => '', 774 '23-blank' => '', 775 776 '24-id-type' => 'SWIFT', 777 '25-id-value' => get_post_meta( $post->ID, '_camppayments_bank_bic', true ), 778 '26-ben-bank-name' => substr( get_post_meta( $post->ID, '_camppayments_bank_name', true ), 0, 35 ), 779 '27-ben-bank-address-1' => substr( get_post_meta( $post->ID, '_camppayments_bank_street_address', true ), 0, 35 ), 780 '28-ben-bank-address-2' => '', 781 '29-ben-bank-address-3' => substr( sprintf( '%s %s %s', 782 get_post_meta( $post->ID, '_camppayments_bank_city', true ), 783 get_post_meta( $post->ID, '_camppayments_bank_state', true ), 784 get_post_meta( $post->ID, '_camppayments_bank_zip_code', true ) 785 ), 0, 35 ), 786 '30-ben-bank-country' => get_post_meta( $post->ID, '_camppayments_bank_country_iso3166', true ), 787 '31-supl-id-type' => '', 788 '32-supl-id-value' => '', 789 790 '33-blank' => '', 791 '34-blank' => '', 792 '35-blank' => '', 793 '36-blank' => '', 794 '37-blank' => '', 795 '38-blank' => '', 796 '39-blank' => '', 797 798 // Filled out later if not empty. 799 '40-id-type' => '', 800 '41-id-value' => '', 801 '42-interm-bank-name' => '', 802 '43-interm-bank-address-1' => '', 803 '44-interm-bank-address-2' => '', 804 '45-interm-bank-address-3' => '', 805 '46-interm-bank-country' => '', 806 '47-supl-id-type' => '', 807 '48-supl-id-value' => '', 808 809 '49-id-type' => '', 810 '50-id-value' => '', 811 '51-party-name' => '', 812 '52-party-address-1' => '', 813 '53-party-address-2' => '', 814 '54-party-address-3' => '', 815 '55-party-country' => '', 816 817 '56-blank' => '', 818 '57-blank' => '', 819 '58-blank' => '', 820 '59-blank' => '', 821 '60-blank' => '', 822 '61-blank' => '', 823 '62-blank' => '', 824 '63-blank' => '', 825 '64-blank' => '', 826 '65-blank' => '', 827 '66-blank' => '', 828 '67-blank' => '', 829 '68-blank' => '', 830 '69-blank' => '', 831 '70-blank' => '', 832 '71-blank' => '', 833 '72-blank' => '', 834 '73-blank' => '', 835 836 '74-ref-text' => substr( get_post_meta( $post->ID, '_camppayments_invoice_number', true ), 0, 16 ), 837 '75-internal-ref' => '', 838 '76-on-behalf-of' => '', 839 840 '77-detial-1' => '', 841 '78-detial-2' => '', 842 '79-detial-3' => '', 843 '80-detail-4' => '', 844 845 '81-blank' => '', 846 '82-blank' => '', 847 '83-blank' => '', 848 '84-blank' => '', 849 '85-blank' => '', 850 '86-blank' => '', 851 '87-blank' => '', 852 '88-blank' => '', 853 854 '89-reporting-code' => '', 855 '90-country' => '', 856 '91-inst-1' => '', 857 '92-inst-2' => '', 858 '93-inst-3' => '', 859 '94-inst-code-1' => '', 860 '95-inst-text-1' => '', 861 '96-inst-code-2' => '', 862 '97-inst-text-2' => '', 863 '98-inst-code-3' => '', 864 '99-inst-text-3' => '', 865 866 '100-stor-code-1' => '', 867 '101-stor-line-2' => '', // Hmm? 868 '102-stor-code-2' => '', 869 '103-stor-line-2' => '', 870 '104-stor-code-3' => '', 871 '105-stor-line-3' => '', 872 '106-stor-code-4' => '', 873 '107-stor-line-4' => '', 874 '108-stor-code-5' => '', 875 '109-stor-line-5' => '', 876 '110-stor-code-6' => '', 877 '111-stor-line-6' => '', 878 879 '112-priority' => '', 880 '113-blank' => '', 881 '114-charges' => '', 882 '115-blank' => '', 883 '116-details' => '', 884 '117-note' => substr( sprintf( 'wcb-%d-%d', $index->blog_id, $index->post_id ), 0, 70 ), 885 ); 886 887 // If an intermediary bank is given. 888 $interm_swift = get_post_meta( $post->ID, '_camppayments_interm_bank_swift', true ); 889 if ( ! empty( $iterm_swift ) ) { 890 $row['40-id-type'] = 'SWIFT'; 891 $row['41-id-value'] = $interm_swift; 892 893 $row['42-interm-bank-name'] = substr( get_post_meta( $post->ID, '_camppayments_interm_bank_name', true ), 0, 35 ); 894 $row['43-interm-bank-address-1'] = substr( get_post_meta( $post->ID, '_camppayments_interm_bank_street_address', true ), 0, 35 ); 895 896 $row['44-interm-bank-address-2'] = ''; 897 $row['45-interm-bank-address-3'] = substr( sprintf( '%s %s %s', 898 get_post_meta( $post->ID, '_camppayments_interm_bank_city', true ), 899 get_post_meta( $post->ID, '_camppayments_interm_bank_state', true ), 900 get_post_meta( $post->ID, '_camppayments_interm_bank_zip_code', true ) 901 ), 0, 32 ); 902 903 $row['46-interm-bank-country'] = get_post_meta( $post->ID, '_camppayments_interm_bank_country_iso3166', true ); 904 905 $row['47-supl-id-type'] = 'ACCT'; 906 $row['48-supl-id-value'] = get_post_meta( $post->ID, '_camppayments_interm_bank_account', true ); 907 } 908 909 // Use for debugging. 910 // print_r( $row ); 911 912 fputcsv( $report, array_values( $row ) ); 913 restore_current_blog(); 914 } 915 916 // JPM Trailer 917 fputcsv( $report, array( 'TRAILER', $count, $total ) ); 918 919 fclose( $report ); 920 $results = ob_get_clean(); 921 922 // JPM chokes on accents and non-latin characters. 923 $results = remove_accents( $results ); 924 return $results; 925 } 926 927 /** 928 * Exclude weekends and JPM holidays. 929 * 930 * Needs to be updated every year. 931 * 932 * @return int Timestamp. 933 */ 934 function _next_business_day_timestamp() { 935 static $timestamp; 936 937 if ( isset( $timestamp ) ) 938 return $timestamp; 939 940 $holidays = array( 941 date( 'Ymd', strtotime( 'Friday, January 1, 2016' ) ), 942 date( 'Ymd', strtotime( 'Monday, January 18, 2016' ) ), 943 date( 'Ymd', strtotime( 'Monday, February 15, 2016' ) ), 944 date( 'Ymd', strtotime( 'Monday, May 30, 2016' ) ), 945 date( 'Ymd', strtotime( 'Monday, July 4, 2016' ) ), 946 date( 'Ymd', strtotime( 'Monday, September 5, 2016' ) ), 947 date( 'Ymd', strtotime( 'Friday, November 11, 2016' ) ), 948 date( 'Ymd', strtotime( 'Thursday, November 24, 2016' ) ), 949 date( 'Ymd', strtotime( 'Monday, December 26, 2016' ) ), 950 ); 951 952 $timestamp = strtotime( 'today + 1 weekday' ); 953 $attempts = 5; 954 955 while ( in_array( date( 'Ymd', $timestamp ), $holidays ) ) { 956 $timestamp = strtotime( '+ 1 weekday', $timestamp ); 957 $attempts--; 958 959 if ( ! $attempts ) 960 break; 961 } 962 963 return $timestamp; 964 } 965 966 /** 34 967 * Remove the empty Budgets submenu item 35 968 * … … 37 970 */ 38 971 function remove_budgets_submenu() { 39 remove_submenu_page( 'wordcamp-budgets-dashboard', 'wordcamp-budgets-dashboard' );972 remove_submenu_page( 'wordcamp-budgets-dashboard', 'wordcamp-budgets-dashboard' ); 40 973 } 41 974 … … 43 976 * Enqueue scripts and styles 44 977 */ 45 function enqueue_scripts( ) {978 function enqueue_scripts( $hook ) { 46 979 wp_enqueue_style( 47 980 'wordcamp-budgets-dashboard', … … 50 983 1 51 984 ); 985 986 if ( $hook == 'budgets_page_wcb-import-export' ) { 987 wp_enqueue_script( 'jquery-ui-datepicker' ); 988 wp_enqueue_style( 'jquery-ui' ); 989 wp_enqueue_style( 'wp-datepicker-skins' ); 990 } 52 991 } 53 992 … … 62 1001 function format_amount( $amount, $currency ) { 63 1002 $formatted_amount = ''; 64 $amount = \WordCamp_Budgets::validate_amount( $amount );1003 $amount = \WordCamp_Budgets::validate_amount( $amount ); 65 1004 66 1005 if ( false === strpos( $currency, 'null' ) && $amount ) { … … 94 1033 global $wpdb; 95 1034 96 $from = strtolower( $from );97 $to = strtolower( $to );1035 $from = strtolower( $from ); 1036 $to = strtolower( $to ); 98 1037 $cache_key = md5( sprintf( 'wcp-exchange-rate-%s:%s', $from, $to ) ); 99 1038 … … 107 1046 108 1047 $request = wp_remote_get( esc_url_raw( $url ) ); 109 $body = json_decode( wp_remote_retrieve_body( $request ), true );1048 $body = json_decode( wp_remote_retrieve_body( $request ), true ); 110 1049 111 1050 if ( ! empty( $body['query']['results']['rate']['Ask'] ) ) {
Note: See TracChangeset
for help on using the changeset viewer.