Changeset 3476201
- Timestamp:
- 03/06/2026 09:21:00 AM (3 weeks ago)
- Location:
- gestoo-connector-for-peppol-invoicing/trunk
- Files:
-
- 2 added
- 4 edited
-
admin/class-gestoo-peppol-order-list-columns.php (added)
-
assets/css/admin.css (modified) (1 diff)
-
assets/js/admin-orders-list.js (added)
-
gestoo-connector-for-peppol-invoicing.php (modified) (4 diffs)
-
includes/class-gestoo-peppol-order-handler.php (modified) (6 diffs)
-
readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
gestoo-connector-for-peppol-invoicing/trunk/assets/css/admin.css
r3474457 r3476201 66 66 outline: 2px solid transparent; 67 67 } 68 69 /* ========================================================================= 70 Orders list columns – Peppol status badges 71 ========================================================================= */ 72 73 .gestoo-peppol-badge { 74 display: inline-block; 75 padding: 2px 7px; 76 border-radius: 3px; 77 font-size: 11px; 78 font-weight: 600; 79 line-height: 1.6; 80 white-space: nowrap; 81 vertical-align: middle; 82 } 83 84 .gestoo-peppol-badge--delivered { 85 background: #d1f0e0; 86 color: #145a32; 87 } 88 89 .gestoo-peppol-badge--invoice-ok { 90 background: #e3f2e1; 91 color: #2d6a2d; 92 } 93 94 .gestoo-peppol-badge--submitted { 95 background: #d6eaf8; 96 color: #154360; 97 } 98 99 .gestoo-peppol-badge--pending { 100 background: #fdebd0; 101 color: #784212; 102 } 103 104 .gestoo-peppol-badge--error { 105 background: #fce8e6; 106 color: #7b241c; 107 } 108 109 .gestoo-peppol-badge--none { 110 background: #f0f0f1; 111 color: #50575e; 112 } 113 114 /* Log info button (ℹ️) */ 115 .gestoo-peppol-log-btn { 116 background: none; 117 border: none; 118 cursor: pointer; 119 padding: 0 3px; 120 font-size: 14px; 121 vertical-align: middle; 122 opacity: .75; 123 } 124 125 .gestoo-peppol-log-btn:hover { 126 opacity: 1; 127 } 128 129 /* Sync/retry button loading state */ 130 .gestoo-peppol-sync-btn.gestoo-peppol-btn-loading { 131 opacity: .6; 132 cursor: wait; 133 } 134 135 /* Inline error under sync button */ 136 .gestoo-peppol-inline-error { 137 display: block; 138 color: #b32d2e; 139 font-size: 11px; 140 margin-top: 3px; 141 } 142 143 /* ========================================================================= 144 Log modal 145 ========================================================================= */ 146 147 #gestoo-peppol-log-modal { 148 position: fixed; 149 top: 0; 150 left: 0; 151 width: 100%; 152 height: 100%; 153 z-index: 160000; /* above WP admin bar (99999) */ 154 } 155 156 .gestoo-peppol-modal-overlay { 157 position: absolute; 158 top: 0; 159 left: 0; 160 width: 100%; 161 height: 100%; 162 background: rgba(0, 0, 0, .55); 163 display: flex; 164 align-items: center; 165 justify-content: center; 166 } 167 168 .gestoo-peppol-modal-box { 169 position: relative; 170 background: #fff; 171 border-radius: 4px; 172 box-shadow: 0 4px 24px rgba(0, 0, 0, .25); 173 padding: 24px 28px 20px; 174 width: 90%; 175 max-width: 620px; 176 max-height: 80vh; 177 overflow-y: auto; 178 } 179 180 .gestoo-peppol-modal-box h3 { 181 margin: 0 0 14px; 182 font-size: 16px; 183 font-weight: 600; 184 color: #1d2327; 185 } 186 187 .gestoo-peppol-modal-close { 188 position: absolute; 189 top: 10px; 190 right: 14px; 191 background: none; 192 border: none; 193 font-size: 22px; 194 line-height: 1; 195 cursor: pointer; 196 color: #646970; 197 padding: 2px 6px; 198 } 199 200 .gestoo-peppol-modal-close:hover { 201 color: #1d2327; 202 } 203 204 /* Last error notice inside modal */ 205 .gestoo-peppol-last-error { 206 background: #fce8e6; 207 border-left: 3px solid #b32d2e; 208 padding: 8px 10px; 209 margin-bottom: 14px; 210 font-size: 13px; 211 color: #3c3c3c; 212 border-radius: 0 3px 3px 0; 213 } 214 215 /* Log table inside modal */ 216 .gestoo-peppol-log-table { 217 width: 100%; 218 border-collapse: collapse; 219 font-size: 13px; 220 } 221 222 .gestoo-peppol-log-table thead th { 223 text-align: left; 224 padding: 6px 8px; 225 border-bottom: 2px solid #dcdcde; 226 color: #3c434a; 227 font-weight: 600; 228 } 229 230 .gestoo-peppol-log-table tbody tr:nth-child(odd) { 231 background: #f6f7f7; 232 } 233 234 .gestoo-peppol-log-table tbody td { 235 padding: 6px 8px; 236 border-bottom: 1px solid #f0f0f1; 237 vertical-align: top; 238 color: #3c434a; 239 } 240 241 .gestoo-peppol-log-date { 242 white-space: nowrap; 243 color: #646970; 244 font-size: 11px; 245 width: 140px; 246 } -
gestoo-connector-for-peppol-invoicing/trunk/gestoo-connector-for-peppol-invoicing.php
r3476162 r3476201 4 4 * Plugin URI: https://www.gestoo.be 5 5 * Description: WooCommerce to GestOO connector: create invoices and send via Peppol. Official invoicing stays in GestOO. 6 * Version: 0. 3.16 * Version: 0.4.0 7 7 * Requires at least: 6.0 8 8 * Requires PHP: 7.4 … … 42 42 ); 43 43 44 define( 'GESTOO_PEPPOL_INVOICE_VERSION', '0. 3.1' );44 define( 'GESTOO_PEPPOL_INVOICE_VERSION', '0.4.0' ); 45 45 define( 'GESTOO_PEPPOL_INVOICE_PLUGIN_FILE', __FILE__ ); 46 46 define( 'GESTOO_PEPPOL_INVOICE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); … … 120 120 require_once GESTOO_PEPPOL_INVOICE_PLUGIN_DIR . 'admin/class-gestoo-peppol-admin-settings.php'; 121 121 require_once GESTOO_PEPPOL_INVOICE_PLUGIN_DIR . 'admin/class-gestoo-peppol-order-meta-box.php'; 122 require_once GESTOO_PEPPOL_INVOICE_PLUGIN_DIR . 'admin/class-gestoo-peppol-order-list-columns.php'; 122 123 require_once GESTOO_PEPPOL_INVOICE_PLUGIN_DIR . 'admin/class-gestoo-peppol-review-prompt.php'; 123 124 … … 128 129 Gestoo_Peppol_Admin_Settings::init(); 129 130 Gestoo_Peppol_Order_Meta_Box::init(); 131 Gestoo_Peppol_Order_List_Columns::init(); 130 132 Gestoo_Peppol_Review_Prompt::init(); 131 133 -
gestoo-connector-for-peppol-invoicing/trunk/includes/class-gestoo-peppol-order-handler.php
r3474457 r3476201 26 26 private const META_LAST_ERROR = '_gestoo_last_error'; 27 27 private const META_SYNC_STATUS = '_gestoo_sync_status'; // Values: pending, synced, error. 28 private const META_ERROR_LOG = '_gestoo_error_log'; // Array of {time, message, context}. 28 29 29 30 /** … … 119 120 $payload = self::build_invoice_payload( $order ); 120 121 if ( null === $payload ) { 122 $err_msg = __( 'Could not build payload (missing order data).', 'gestoo-connector-for-peppol-invoicing' ); 121 123 $order->update_meta_data( self::META_SYNC_STATUS, 'error' ); 122 $order->update_meta_data( self::META_LAST_ERROR, __( 'Could not build payload (missing order data).', 'gestoo-connector-for-peppol-invoicing' ) ); 124 $order->update_meta_data( self::META_LAST_ERROR, $err_msg ); 125 self::append_error_log( $order, $err_msg, 'build_payload' ); 123 126 $order->save(); 124 127 return; … … 128 131 129 132 if ( ! $result['success'] ) { 133 $err_msg = $result['message'] ?? __( 'Unknown error', 'gestoo-connector-for-peppol-invoicing' ); 130 134 $order->update_meta_data( self::META_SYNC_STATUS, 'error' ); 131 $order->update_meta_data( self::META_LAST_ERROR, $result['message'] ?? __( 'Unknown error', 'gestoo-connector-for-peppol-invoicing' ) ); 135 $order->update_meta_data( self::META_LAST_ERROR, $err_msg ); 136 self::append_error_log( $order, $err_msg, 'create_invoice' ); 132 137 $order->save(); 133 138 return; … … 137 142 $invoice_id = (int) ( $data['invoice_id'] ?? 0 ); 138 143 if ( 0 >= $invoice_id ) { 144 $err_msg = __( 'Invalid API response (invoice_id missing).', 'gestoo-connector-for-peppol-invoicing' ); 139 145 $order->update_meta_data( self::META_SYNC_STATUS, 'error' ); 140 $order->update_meta_data( self::META_LAST_ERROR, __( 'Invalid API response (invoice_id missing).', 'gestoo-connector-for-peppol-invoicing' ) ); 146 $order->update_meta_data( self::META_LAST_ERROR, $err_msg ); 147 self::append_error_log( $order, $err_msg, 'create_invoice' ); 141 148 $order->save(); 142 149 return; … … 156 163 $order->save(); 157 164 } else { 165 166 $err_msg = $send_result['message'] ?? ''; 158 167 $order->update_meta_data( self::META_PEPPOL_STATUS, 'error' ); 159 $order->update_meta_data( self::META_PEPPOL_MESSAGE, $send_result['message'] ?? '' ); 168 $order->update_meta_data( self::META_PEPPOL_MESSAGE, $err_msg ); 169 if ( '' !== $err_msg ) { 170 self::append_error_log( $order, $err_msg, 'send_peppol' ); 171 } 160 172 $order->save(); 161 173 } … … 374 386 return self::META_SYNC_STATUS; 375 387 } 388 389 /** 390 * Meta key for error log. 391 * 392 * @return string 393 */ 394 public static function meta_error_log(): string { 395 return self::META_ERROR_LOG; 396 } 397 398 /** 399 * Append an entry to the order's error log (max 20 entries). 400 * Caller must call $order->save() afterwards. 401 * 402 * @param WC_Order $order Order object. 403 * @param string $message Error message. 404 * @param string $context Short context key (e.g. 'create_invoice', 'send_peppol'). 405 */ 406 public static function append_error_log( WC_Order $order, string $message, string $context = '' ): void { 407 $log = $order->get_meta( self::META_ERROR_LOG ); 408 if ( ! is_array( $log ) ) { 409 $log = []; 410 } 411 $log[] = [ 412 'time' => current_time( 'mysql' ), 413 'message' => $message, 414 'context' => $context, 415 ]; 416 if ( count( $log ) > 20 ) { 417 $log = array_slice( $log, -20 ); 418 } 419 $order->update_meta_data( self::META_ERROR_LOG, $log ); 420 } 421 422 /** 423 * Smart sync: create invoice in GestOO if not yet created, or refresh Peppol status if already created. 424 * Idempotent: calling multiple times is safe (GestOO handles deduplication via idempotency_key). 425 * 426 * @param WC_Order $order Order to sync. 427 * @return array{ success: bool, message: string } 428 */ 429 public static function sync_order_now( WC_Order $order ): array { 430 $client = self::get_api_client(); 431 if ( null === $client ) { 432 return [ 433 'success' => false, 434 'message' => __( 'GestOO API not configured.', 'gestoo-connector-for-peppol-invoicing' ), 435 ]; 436 } 437 438 $invoice_id = (int) $order->get_meta( self::META_INVOICE_ID ); 439 440 if ( $invoice_id <= 0 ) { 441 // No invoice yet → try to create it. 442 if ( ! self::has_tax_rates_configured() ) { 443 return [ 444 'success' => false, 445 'message' => __( 'VAT rates must be configured in WooCommerce to generate Peppol invoices.', 'gestoo-connector-for-peppol-invoicing' ), 446 ]; 447 } 448 $payload = self::build_invoice_payload( $order ); 449 if ( null === $payload ) { 450 return [ 451 'success' => false, 452 'message' => __( 'Insufficient order data (missing billing email).', 'gestoo-connector-for-peppol-invoicing' ), 453 ]; 454 } 455 $result = $client->create_invoice( $payload ); 456 if ( ! $result['success'] ) { 457 $msg = $result['message'] ?? __( 'Unknown error', 'gestoo-connector-for-peppol-invoicing' ); 458 $order->update_meta_data( self::META_SYNC_STATUS, 'error' ); 459 $order->update_meta_data( self::META_LAST_ERROR, $msg ); 460 self::append_error_log( $order, $msg, 'create_invoice' ); 461 $order->save(); 462 return [ 'success' => false, 'message' => $msg ]; 463 } 464 $data = $result['data'] ?? []; 465 $invoice_id = (int) ( $data['invoice_id'] ?? 0 ); 466 if ( $invoice_id <= 0 ) { 467 $msg = __( 'Invalid API response (invoice_id missing).', 'gestoo-connector-for-peppol-invoicing' ); 468 $order->update_meta_data( self::META_SYNC_STATUS, 'error' ); 469 $order->update_meta_data( self::META_LAST_ERROR, $msg ); 470 self::append_error_log( $order, $msg, 'create_invoice' ); 471 $order->save(); 472 return [ 'success' => false, 'message' => $msg ]; 473 } 474 $order->update_meta_data( self::META_INVOICE_ID, $invoice_id ); 475 $order->update_meta_data( self::META_INVOICE_NUMBER, $data['invoice_number'] ?? '' ); 476 $order->update_meta_data( self::META_SYNC_STATUS, 'synced' ); 477 $order->delete_meta_data( self::META_LAST_ERROR ); 478 $order->save(); 479 if ( self::is_auto_send_peppol() ) { 480 $send = $client->send_peppol( $invoice_id ); 481 if ( $send['success'] && isset( $send['data']['peppol_status'] ) ) { 482 $order->update_meta_data( self::META_PEPPOL_STATUS, $send['data']['peppol_status'] ); 483 $order->update_meta_data( self::META_PEPPOL_MESSAGE, $send['data']['peppol_message'] ?? '' ); 484 $order->save(); 485 } else { 486 $msg = $send['message'] ?? __( 'Peppol send error.', 'gestoo-connector-for-peppol-invoicing' ); 487 $order->update_meta_data( self::META_PEPPOL_STATUS, 'error' ); 488 $order->update_meta_data( self::META_PEPPOL_MESSAGE, $msg ); 489 self::append_error_log( $order, $msg, 'send_peppol' ); 490 $order->save(); 491 } 492 } 493 return [ 'success' => true, 'message' => __( 'Invoice created.', 'gestoo-connector-for-peppol-invoicing' ) ]; 494 } 495 496 // Invoice already exists → refresh Peppol status from GestOO. 497 self::refresh_peppol_status( $order, $client ); 498 return [ 'success' => true, 'message' => __( 'Status refreshed.', 'gestoo-connector-for-peppol-invoicing' ) ]; 499 } 376 500 } -
gestoo-connector-for-peppol-invoicing/trunk/readme.txt
r3476162 r3476201 2 2 3 3 Contributors: webdigit 4 Tags: woocommerce, peppol, invoice, e-invoicing , ubl, b2b, gestoo4 Tags: woocommerce, peppol, invoice, e-invoicing 5 5 Requires at least: 6.0 6 6 Tested up to: 6.9 7 Stable tag: 0. 3.17 Stable tag: 0.4.0 8 8 Requires PHP: 7.4 9 9 Requires Plugins: woocommerce … … 80 80 == Changelog == 81 81 82 = 0.4.0 = 83 * Added Peppol status columns in the WooCommerce orders list (HPOS + legacy compatible). 84 * Added smart sync/retry button in the orders list: creates invoice if missing, refreshes Peppol status if already sent. 85 * Added event log modal (ℹ button) showing timestamped error history per order. 86 * Stored error log (up to 20 entries) in order meta for diagnostics. 87 82 88 = 0.3.1 = 83 89 * Added review prompt (J+30 after activation) to help users rate the plugin. … … 105 111 == Upgrade Notice == 106 112 113 = 0.4.0 = 114 Adds Peppol status columns and sync/retry button in the orders list. Safe to update. 115 107 116 = 0.3.1 = 108 117 Adds review prompt and uninstall cleanup. Safe to update.
Note: See TracChangeset
for help on using the changeset viewer.