Changeset 3720581
- Timestamp:
- 09/30/2026 07:50:27 AM (3 weeks ago)
- Location:
- philia-integration
- Files:
-
- 19 added
- 2 deleted
- 12 edited
-
tags/1.18.1/readme.txt (deleted)
-
tags/1.18.2/readme.txt (deleted)
-
tags/1.19 (added)
-
tags/1.19/assets (added)
-
tags/1.19/assets/philia-api-settings.js (added)
-
tags/1.19/assets/philia-api-sync.js (added)
-
tags/1.19/assets/philia-login-redirect.js (added)
-
tags/1.19/assets/philia-wallet.js (added)
-
tags/1.19/includes (added)
-
tags/1.19/includes/class-api-log.php (added)
-
tags/1.19/includes/class-api-settings.php (added)
-
tags/1.19/includes/class-core-api.php (added)
-
tags/1.19/includes/class-event-sender.php (added)
-
tags/1.19/includes/class-login-redirect.php (added)
-
tags/1.19/includes/class-philia-referral.php (added)
-
tags/1.19/includes/class-philia-wallet.php (added)
-
tags/1.19/includes/class-webhook-sender.php (added)
-
tags/1.19/includes/templates (added)
-
tags/1.19/includes/templates/philia-wallet-payment.php (added)
-
tags/1.19/philia-integration.php (added)
-
tags/1.19/readme.txt (added)
-
trunk/assets/philia-wallet.js (modified) (7 diffs)
-
trunk/includes/class-api-log.php (modified) (1 diff)
-
trunk/includes/class-api-settings.php (modified) (23 diffs)
-
trunk/includes/class-core-api.php (modified) (7 diffs)
-
trunk/includes/class-event-sender.php (modified) (15 diffs)
-
trunk/includes/class-login-redirect.php (modified) (1 diff)
-
trunk/includes/class-philia-referral.php (modified) (1 diff)
-
trunk/includes/class-philia-wallet.php (modified) (15 diffs)
-
trunk/includes/class-webhook-sender.php (modified) (4 diffs)
-
trunk/includes/templates/philia-wallet-payment.php (modified) (2 diffs)
-
trunk/philia-integration.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
philia-integration/trunk/assets/philia-wallet.js
r3683158 r3720581 6 6 } 7 7 8 var isActive = Boolean(philiaWalletParams.isActive); 8 var walletActive = Boolean(philiaWalletParams.isActive); 9 var cashbackActive = null; 10 var currentBalance = 0; 9 11 var isToggling = false; 10 12 var activeGateway = $('input[name="payment_method"]:checked').val() || ''; … … 14 16 } 15 17 16 function fetchAndDisplayBalance() { 17 $.post(philiaWalletParams.ajaxUrl, { 18 action: 'philia_get_wallet_balance', 19 nonce: philiaWalletParams.nonce 20 }).done(function (response) { 21 if (!response.success) { 22 return; 23 } 24 25 var balance = parseFloat(response.data.user_cashback) || 0; 26 $('.philia-wallet-balance').text(formatPrice(balance) + ' ' + response.data.currency); 27 28 var $toggle = $('.partial_pay_through_wallet'); 29 var $container = $('.philia-wallet-checkout-container'); 30 31 if (balance <= 0 && !isActive) { 32 $toggle.prop('checked', false).prop('disabled', true); 33 $container.addClass('philia-disabled'); 34 } else { 35 enforceGatewayRestriction(balance); 36 } 37 }); 18 function toBoolean(value) { 19 return value === true || value === 1 || value === '1' || value === 'true'; 38 20 } 39 21 40 function enforceGatewayRestriction(balance) { 22 function hasOwn(object, property) { 23 return object && Object.prototype.hasOwnProperty.call(object, property); 24 } 25 26 function updateToggleUI() { 27 $('.partial_pay_through_wallet').prop('checked', walletActive); 28 } 29 30 function applyWalletAvailability(suppressAutoToggle) { 41 31 var $toggle = $('.partial_pay_through_wallet'); 42 32 var $container = $('.philia-wallet-checkout-container'); 43 33 var selected = $('input[name="payment_method"]:checked').val() || ''; 44 34 45 if (balance <= 0 && !isActive) { 35 updateToggleUI(); 36 37 if (cashbackActive !== true) { 46 38 $toggle.prop('disabled', true); 47 39 $container.addClass('philia-disabled'); … … 49 41 } 50 42 51 if (!selected && isActive) { 43 if (currentBalance <= 0 && !walletActive) { 44 $toggle.prop('disabled', true); 45 $container.addClass('philia-disabled'); 46 return; 47 } 48 49 if (!selected && walletActive) { 52 50 $toggle.prop('disabled', false); 53 51 $container.removeClass('philia-disabled'); … … 56 54 57 55 if (philiaWalletParams.enabledGateways.indexOf(selected) !== -1) { 58 if ( isActive) {56 if (walletActive) { 59 57 activeGateway = selected; 60 58 } 59 61 60 $toggle.prop('disabled', false); 62 61 $container.removeClass('philia-disabled'); 63 } else { 64 if ($toggle.is(':checked')) { 65 $toggle.prop('checked', false); 66 callToggle(false); 67 } 68 $toggle.prop('disabled', true); 69 $container.addClass('philia-disabled'); 62 return; 63 } 64 65 $toggle.prop('disabled', true); 66 $container.addClass('philia-disabled'); 67 68 if (walletActive && !isToggling && !suppressAutoToggle) { 69 callToggle(false); 70 70 } 71 71 } 72 72 73 function updateToggleUI() { 74 $('.partial_pay_through_wallet').prop('checked', isActive); 73 function fetchAndDisplayBalance() { 74 $.post(philiaWalletParams.ajaxUrl, { 75 action: 'philia_get_wallet_balance', 76 nonce: philiaWalletParams.nonce 77 }).done(function (response) { 78 if (!response.success || !response.data) { 79 cashbackActive = false; 80 applyWalletAvailability(true); 81 return; 82 } 83 84 currentBalance = parseFloat(response.data.user_cashback) || 0; 85 cashbackActive = toBoolean(response.data.is_active); 86 87 if (hasOwn(response.data, 'wallet_active')) { 88 walletActive = toBoolean(response.data.wallet_active); 89 } 90 91 $('.philia-wallet-balance').text( 92 formatPrice(currentBalance) + ' ' + response.data.currency 93 ); 94 95 applyWalletAvailability(false); 96 }).fail(function () { 97 cashbackActive = false; 98 applyWalletAvailability(true); 99 }); 75 100 } 76 101 77 102 function callToggle(enabled) { 78 103 if (isToggling) { 104 updateToggleUI(); 79 105 return; 80 106 } … … 82 108 isToggling = true; 83 109 110 var previousActive = walletActive; 111 var stateChanged = false; 112 var requestFailed = false; 84 113 var $orderReview = $('.woocommerce-checkout-review-order-table'); 114 115 $('.partial_pay_through_wallet').prop('disabled', true); 116 85 117 if ($.isFunction($orderReview.block)) { 86 118 $orderReview.block({ … … 96 128 payment_method: $('input[name="payment_method"]:checked').val() || activeGateway || '' 97 129 }).done(function (response) { 130 var data = response && response.data ? response.data : {}; 131 132 if (hasOwn(data, 'wallet_active')) { 133 walletActive = toBoolean(data.wallet_active); 134 } else if (response.success) { 135 walletActive = enabled; 136 } else { 137 walletActive = previousActive; 138 } 139 140 if (hasOwn(data, 'cashback_active')) { 141 cashbackActive = toBoolean(data.cashback_active); 142 } 143 144 stateChanged = walletActive !== previousActive; 145 requestFailed = !response.success; 146 updateToggleUI(); 147 98 148 if (response.success) { 99 isActive = enabled; 100 activeGateway = enabled 149 activeGateway = walletActive 101 150 ? ($('input[name="payment_method"]:checked').val() || activeGateway || '') 102 151 : ''; 152 } 153 154 if (response.success || stateChanged) { 103 155 $(document.body).trigger('update_checkout'); 104 fetchAndDisplayBalance();105 156 } else { 106 isActive = false; 107 updateToggleUI(); 108 fetchAndDisplayBalance(); 157 applyWalletAvailability(true); 109 158 } 159 }).fail(function () { 160 requestFailed = true; 161 walletActive = previousActive; 162 updateToggleUI(); 163 applyWalletAvailability(true); 110 164 }).always(function () { 111 165 isToggling = false; 166 112 167 if ($.isFunction($orderReview.unblock)) { 113 168 $orderReview.unblock(); 114 169 } 170 171 applyWalletAvailability(requestFailed); 115 172 }); 116 173 } … … 126 183 127 184 updateToggleUI(); 185 applyWalletAvailability(true); 128 186 fetchAndDisplayBalance(); 129 187 }(jQuery)); -
philia-integration/trunk/includes/class-api-log.php
r3583389 r3720581 1 1 <?php 2 2 /** 3 * PhiliaAPI Log4 * The class responsible for handling logging in the PhiliaAPI plugin.3 * Legion API Log 4 * The class responsible for handling logging in the Legion API plugin. 5 5 * 6 * Package: Philia7 * Author: Philia6 * Package: Legion 7 * Author: Legion 8 8 */ 9 9 -
philia-integration/trunk/includes/class-api-settings.php
r3683431 r3720581 1 1 <?php 2 2 /** 3 * PhiliaAPI Settings4 * The class responsible for managing the PhiliaAPI settings in WordPress.3 * Legion API Settings 4 * The class responsible for managing the Legion API settings in WordPress. 5 5 * 6 * Package: Philia7 * Author: Philia6 * Package: Legion 7 * Author: Legion 8 8 */ 9 9 … … 81 81 add_submenu_page( 82 82 'philia-api-settings', 83 __(' PhiliaAPI Settings', 'philia-integration'), // Page title83 __('Legion API Settings', 'philia-integration'), // Page title 84 84 __('Settings', 'philia-integration'), // Menu title 85 85 'manage_options', // Capability … … 167 167 ); 168 168 169 // Wallet display title 170 add_settings_field( 171 'wallet_title', 172 __('Wallet Title', 'philia-integration'), 173 array($this, 'wallet_title_field_callback'), 174 'philia-api-settings', 175 'philia_api_settings_section' 176 ); 177 169 178 // Wallet Enabled Payment Gateways 170 179 add_settings_field( … … 179 188 add_settings_field( 180 189 'philia_product_id_fill_mode', 181 __('Auto-fill PhiliaProduct ID', 'philia-integration'),190 __('Auto-fill Legion Product ID', 'philia-integration'), 182 191 array($this, 'philia_product_id_fill_mode_field_callback'), 183 192 'philia-api-settings', … … 198 207 <div class="notice"> 199 208 <p> 200 <?php esc_attr_e('Click the "Test Connection" button to check the connection to Philia.', 'philia-integration'); ?>209 <?php esc_attr_e('Click the "Test Connection" button to check the connection to Legion.', 'philia-integration'); ?> 201 210 <button id="test-philia-connection" class="button"><?php echo esc_attr__('Test Connection','philia-integration'); ?></button> 202 211 </p> … … 210 219 { 211 220 $res = self::create_and_send_woocommerce_api_key( $settings['api_url'] , $settings['api_key'], $settings['phone_meta'], $settings['data_sync'], $settings['order_sync_status'], $settings['philia_product_id_fill_mode'] ); 212 error_log("RESPONSE FROM SAVE SETTINGS : " . print_r($res, true ) );213 221 if( wp_remote_retrieve_response_code( $res ) == 200 ) 214 222 { 215 223 ?> 216 224 <div class="notice notice-success is-dismissible"> 217 <p><?php esc_html_e('The Synchronization with Philiahas been successfully configured.', 'philia-integration'); ?></p>225 <p><?php esc_html_e('The Synchronization with Legion has been successfully configured.', 'philia-integration'); ?></p> 218 226 </div> 219 227 <?php … … 231 239 <hr> 232 240 <h1><?php echo esc_attr__('Shortcodes', 'philia-integration'); ?></h1> 233 <p><?php echo esc_html__('Use the following shortcodes to display Philiafeatures on your pages.', 'philia-integration'); ?></p>241 <p><?php echo esc_html__('Use the following shortcodes to display Legion features on your pages.', 'philia-integration'); ?></p> 234 242 <table class="form-table"> 235 243 <tbody> … … 291 299 ?> 292 300 <input type="text" name="philia_api_settings[api_key]" value="<?php echo esc_attr( $settings['api_key'] ?? ''); ?>" size="50" /> 293 <p class="description"><?php echo esc_attr__('Please enter the access key for the Philiaweb service.', 'philia-integration'); ?></p>301 <p class="description"><?php echo esc_attr__('Please enter the access key for the Legion web service.', 'philia-integration'); ?></p> 294 302 <?php 295 303 } … … 317 325 ?> 318 326 </select> 319 <p class="description"><?php echo esc_attr__('The meta key of the phone is required for syncing users with Philia. If not selected, the synchronization process will not take place.', 'philia-integration'); ?></p>327 <p class="description"><?php echo esc_attr__('The meta key of the phone is required for syncing users with Legion. If not selected, the synchronization process will not take place.', 'philia-integration'); ?></p> 320 328 <?php 321 329 } 322 330 323 331 /** 324 * Outputs the dropdown for order statussynchronization.332 * Outputs the order statuses available for synchronization. 325 333 * 326 334 * @return void … … 329 337 { 330 338 $settings = get_option('philia_api_settings'); 331 332 // Get the selected order status, default to 'completed' 333 $selected_status = isset($settings['order_sync_status']) ? $settings['order_sync_status'] : 'completed'; 339 340 $selected_status = self::normalize_order_sync_status( 341 isset( $settings['order_sync_status'] ) ? $settings['order_sync_status'] : 'completed' 342 ); 334 343 335 344 if ( ! function_exists( 'wc_get_order_statuses' ) ) { … … 338 347 } 339 348 340 // Get all available WooCommerce order statuses341 349 $order_statuses = wc_get_order_statuses(); 342 343 echo '<select name="philia_api_settings[order_sync_status]" id="philia-order-sync-status">'; 344 foreach ($order_statuses as $status_key => $status_label) { 345 // Remove 'wc-' prefix from status key 346 $status_value = str_replace('wc-', '', $status_key); 347 $selected = selected($selected_status, $status_value, false); 348 echo '<option value="' . esc_attr($status_value) . '" ' . $selected . '>' . esc_html($status_label) . '</option>'; 350 351 echo '<select id="philia-order-sync-status" name="philia_api_settings[order_sync_status]">'; 352 foreach ( $order_statuses as $status_key => $status_label ) { 353 $status_value = 0 === strpos( $status_key, 'wc-' ) ? substr( $status_key, 3 ) : $status_key; 354 echo '<option value="' . esc_attr( $status_value ) . '" ' . selected( $selected_status, $status_value, false ) . '>' . esc_html( $status_label ) . '</option>'; 349 355 } 350 356 echo '</select>'; 351 357 ?> 352 <p class="description"><?php echo esc_ attr__('Select which order status should trigger synchronization with Philia. Only orders with this status will be sent.', 'philia-integration'); ?></p>358 <p class="description"><?php echo esc_html__('Orders are synchronized with Legion only when they reach the selected status.', 'philia-integration'); ?></p> 353 359 <?php 354 360 } … … 394 400 __('Customer', 'philia-integration') => '4', 395 401 __('Engagement Events', 'philia-integration') => '5', 402 __('Refunded Order', 'philia-integration') => '6', 396 403 ]; 397 404 … … 423 430 echo '</fieldset>'; 424 431 ?> 425 <p class="description"><?php echo esc_attr__('Select the data types you want to sync with Philia.', 'philia-integration'); ?></p> 432 <p class="description"><?php echo esc_attr__('Select the data types you want to sync with Legion.', 'philia-integration'); ?></p> 433 <?php 434 } 435 436 /** 437 * Outputs the wallet title used on WooCommerce orders and invoices. 438 * 439 * @return void 440 */ 441 public function wallet_title_field_callback() 442 { 443 ?> 444 <input type='text' id='philia-wallet-title' name='philia_api_settings[wallet_title]' value='<?php echo esc_attr( self::get_wallet_title() ); ?>' class='regular-text' /> 445 <p class='description'><?php echo esc_html__( 'This title is displayed for wallet payments on orders and invoices.', 'philia-integration' ); ?></p> 426 446 <?php 427 447 } … … 486 506 } 487 507 echo '</select>'; 488 echo '<p class="description">' . esc_html__('Determines how the philiaproduct id is auto-filled when a new product is saved and the field is empty.', 'philia-integration') . '</p>';508 echo '<p class="description">' . esc_html__('Determines how the legion product id is auto-filled when a new product is saved and the field is empty.', 'philia-integration') . '</p>'; 489 509 } 490 510 … … 495 515 */ 496 516 public function philia_api_settings_section_callback() { 497 echo '<p>' . esc_attr__('Configure the PhiliaAPI settings below.', 'philia-integration') . '</p>';517 echo '<p>' . esc_attr__('Configure the Legion API settings below.', 'philia-integration') . '</p>'; 498 518 } 499 519 … … 548 568 } 549 569 550 // Sanitize order sync status551 if (isset($input['order_sync_status'])) {552 $sanitized_input[' order_sync_status'] = sanitize_text_field($input['order_sync_status']);570 if ( isset( $input['wallet_title'] ) ) { 571 $wallet_title = sanitize_text_field( $input['wallet_title'] ); 572 $sanitized_input['wallet_title'] = $wallet_title !== '' ? $wallet_title : self::get_default_wallet_title(); 553 573 } else { 554 // Default to 'completed' if not set 555 $sanitized_input['order_sync_status'] = 'completed'; 556 } 574 $sanitized_input['wallet_title'] = self::get_default_wallet_title(); 575 } 576 577 // Only one registered WooCommerce order status may trigger synchronization. 578 $sanitized_input['order_sync_status'] = self::normalize_order_sync_status( 579 isset( $input['order_sync_status'] ) ? $input['order_sync_status'] : 'completed' 580 ); 557 581 558 582 // Sanitize product ID fill mode … … 654 678 'version' => $version, 655 679 'plugin_version' => PHILIA_PLUGIN_VERSION, 656 'order_sync_status' => ( isset( $order_sync_status ) && ! is_null( $order_sync_status ) ) ? sanitize_text_field( $order_sync_status ) : 'completed',680 'order_sync_status' => self::normalize_order_sync_status( $order_sync_status ), 657 681 'rest_prefix' => $rest_prefix, // Include the current REST API prefix, 658 682 'data_sync' => $philia_data_sync, … … 760 784 */ 761 785 public function add_bulk_action_fill_philia_product_id($bulk_actions) { 762 $bulk_actions['fill_philia_product_id'] = __('Fill PhiliaProduct ID', 'philia-integration');786 $bulk_actions['fill_philia_product_id'] = __('Fill Legion Product ID', 'philia-integration'); 763 787 return $bulk_actions; 764 788 } … … 845 869 printf( 846 870 /* translators: %1$d: number of filled products, %2$d: number of skipped products */ 847 esc_html__(' PhiliaProduct ID filled for %1$d product(s). %2$d product(s) skipped (already filled, no SKU available, or mode is Custom).', 'philia-integration'),871 esc_html__('Legion Product ID filled for %1$d product(s). %2$d product(s) skipped (already filled, no SKU available, or mode is Custom).', 'philia-integration'), 848 872 $filled, 849 873 $skipped … … 1071 1095 * Checks if a specific data sync option is enabled. 1072 1096 * 1073 * @param string $key_to_check The value to check for (e.g., '1', '2', '3', '4', '5').1097 * @param string $key_to_check The value to check for (e.g., '1', '2', '3', '4', '5', '6'). 1074 1098 * @return bool True if the key is in the data_sync array, false otherwise. 1075 1099 */ … … 1111 1135 1112 1136 /** 1137 * Get the default wallet display title. 1138 * 1139 * @return string 1140 */ 1141 public static function get_default_wallet_title() 1142 { 1143 return __('Legion Wallet', 'philia-integration'); 1144 } 1145 1146 /** 1147 * Get the configured wallet display title. 1148 * 1149 * @return string 1150 */ 1151 public static function get_wallet_title() 1152 { 1153 $settings = get_option( 'philia_api_settings' ); 1154 $title = isset( $settings['wallet_title'] ) ? sanitize_text_field( $settings['wallet_title'] ) : ''; 1155 1156 return $title !== '' ? $title : self::get_default_wallet_title(); 1157 } 1158 1159 /** 1113 1160 * Get the payment gateways where Philia wallet partial payment is enabled. 1114 1161 * … … 1183 1230 1184 1231 /** 1185 * Get the order status that should trigger synchronization.1186 * 1187 * @return string The order status slug (e.g., 'completed', 'processing')1232 * Get the order statuses that should trigger synchronization. 1233 * 1234 * @return string The selected order status slug. 1188 1235 */ 1189 1236 public static function get_order_sync_status() … … 1192 1239 $settings = get_option( 'philia_api_settings' ); 1193 1240 1194 // Return the saved status or default to 'completed' 1195 return isset( $settings['order_sync_status'] ) ? $settings['order_sync_status'] : 'completed'; 1241 return self::normalize_order_sync_status( 1242 isset( $settings['order_sync_status'] ) ? $settings['order_sync_status'] : 'completed' 1243 ); 1244 } 1245 1246 /** 1247 * Normalizes the selected order status and limits it to registered WooCommerce values. 1248 * 1249 * Completed is used as the fallback when the value is missing or invalid. 1250 * 1251 * @param string|array|null $status Selected order status. Arrays are accepted for legacy settings. 1252 * @return string 1253 */ 1254 private static function normalize_order_sync_status( $status ) 1255 { 1256 if ( is_array( $status ) ) { 1257 $status = reset( $status ); 1258 } 1259 1260 $status = is_scalar( $status ) ? sanitize_key( (string) $status ) : ''; 1261 $status = 0 === strpos( $status, 'wc-' ) ? substr( $status, 3 ) : $status; 1262 1263 if ( function_exists( 'wc_get_order_statuses' ) ) { 1264 foreach ( array_keys( wc_get_order_statuses() ) as $status_key ) { 1265 $allowed_status = 0 === strpos( $status_key, 'wc-' ) ? substr( $status_key, 3 ) : $status_key; 1266 if ( $status === $allowed_status ) { 1267 return $status; 1268 } 1269 } 1270 } 1271 1272 return 'completed'; 1196 1273 } 1197 1274 -
philia-integration/trunk/includes/class-core-api.php
r3683431 r3720581 1 1 <?php 2 2 /** 3 * PhiliaCore API4 * This class handles API requests to the configured PhiliaAPI endpoint.3 * Legion Core API 4 * This class handles API requests to the configured Legion API endpoint. 5 5 * 6 * Package: Philia7 * Author: Philia6 * Package: Legion 7 * Author: Legion 8 8 */ 9 9 … … 26 26 27 27 /** 28 * Endpoint used to exchange a PhiliaAPI key for a JWT access token.28 * Endpoint used to exchange a Legion API key for a JWT access token. 29 29 * 30 30 * @var string … … 85 85 if (!empty( $settings ) && empty($settings['api_url'])) { 86 86 //error_log("API URL is not configured in the settings."); 87 // throw new \Exception(__('API URL is not configured. Please set it in the PhiliaAPI settings.', 'philia-integration'));87 // throw new \Exception(__('API URL is not configured. Please set it in the Legion API settings.', 'philia-integration')); 88 88 } 89 89 } … … 168 168 169 169 if ($api_key === '') { 170 return new \WP_Error('philia_api_key_missing', 'The PhiliaAPI key is not set.');170 return new \WP_Error('philia_api_key_missing', 'The Legion API key is not set.'); 171 171 } 172 172 … … 201 201 return new \WP_Error( 202 202 'philia_jwt_request_failed', 203 'Failed to retrieve a Philiaaccess token.',203 'Failed to retrieve a Legion access token.', 204 204 array('status' => $status_code, 'response' => $response_body) 205 205 ); … … 213 213 return new \WP_Error( 214 214 'philia_jwt_invalid_response', 215 'The Philiatoken response did not contain an access token.',215 'The Legion token response did not contain an access token.', 216 216 array('status' => $status_code, 'response' => $response_body) 217 217 ); … … 241 241 242 242 if (empty($settings['api_key'])) { 243 error_log("Error occurred: The API key is not set. Please configure the API key in the PhiliaAPI settings.");243 error_log("Error occurred: The API key is not set. Please configure the API key in the Legion API settings."); 244 244 return; 245 245 } -
philia-integration/trunk/includes/class-event-sender.php
r3683158 r3720581 1 1 <?php 2 2 /** 3 * PhiliaEvent Sender4 * Sends engagement events to Philiaindependently from data-sync webhooks.3 * Legion Event Sender 4 * Sends engagement events to Legion independently from data-sync webhooks. 5 5 * 6 * Package: Philia7 * Author: Philia6 * Package: Legion 7 * Author: Legion 8 8 */ 9 9 … … 18 18 private const EVENT_ID = 44; 19 19 private const FORM_EVENT_ID = 3; 20 private const ADD_TO_CART_EVENT_ID = 43; 21 private const REFUNDED_ORDER_EVENT_ID = 45; 20 22 21 23 /** @var Philia_Event_Sender|null */ … … 87 89 88 90 /** 89 * Registers all engagement hooks controlled by data-sync setting 5.91 * Registers event hooks controlled by their respective data-sync settings. 90 92 * 91 93 * @return void … … 102 104 103 105 try { 104 $enabled = (bool) Philia_API_Settings::is_philia_data_sync_enabled( '5' ); 106 $engagement_enabled = (bool) Philia_API_Settings::is_philia_data_sync_enabled( '5' ); 107 $refunds_enabled = (bool) Philia_API_Settings::is_philia_data_sync_enabled( '6' ); 105 108 } catch ( \Throwable $exception ) { 106 error_log( 'Philia_Event_Sender: Failed checking e ngagement sync setting: ' . $exception->getMessage() );109 error_log( 'Philia_Event_Sender: Failed checking event sync settings: ' . $exception->getMessage() ); 107 110 return; 108 111 } 109 112 110 113 $this->event_actions_registered = true; 111 if ( ! $enabled ) { 112 return; 113 } 114 115 $actions = array( 116 'philia_viewed', 117 'comment_post', 118 'transition_comment_status', 119 'spammed_comment', 120 'deleted_comment', 121 'woocommerce_add_to_cart', 122 ); 123 124 foreach ( $actions as $action ) { 125 add_action( $action, array( $this, 'queue_event_callback' ), 10, 99 ); 126 } 127 128 // Optional integrations; the hooks are harmless when these plugins are inactive. 129 add_action( 'gform_after_submission', array( $this, 'handle_gravity_forms_submission' ), 10, 2 ); 130 add_action( 'wpcf7_mail_sent', array( $this, 'handle_contact_form_7_submission' ), 10, 1 ); 131 add_action( 'wpforms_process_complete', array( $this, 'handle_wpforms_submission' ), 10, 4 ); 114 if ( $engagement_enabled ) { 115 $actions = array( 116 'philia_viewed', 117 'comment_post', 118 'transition_comment_status', 119 'spammed_comment', 120 'deleted_comment', 121 'woocommerce_add_to_cart', 122 ); 123 124 foreach ( $actions as $action ) { 125 add_action( $action, array( $this, 'queue_event_callback' ), 10, 99 ); 126 } 127 128 // Optional integrations; the hooks are harmless when these plugins are inactive. 129 add_action( 'gform_after_submission', array( $this, 'handle_gravity_forms_submission' ), 10, 2 ); 130 add_action( 'wpcf7_mail_sent', array( $this, 'handle_contact_form_7_submission' ), 10, 1 ); 131 add_action( 'wpforms_process_complete', array( $this, 'handle_wpforms_submission' ), 10, 4 ); 132 } 133 134 if ( $refunds_enabled ) { 135 add_action( 'woocommerce_order_refunded', array( $this, 'queue_event_callback' ), 10, 2 ); 136 } 132 137 } 133 138 … … 144 149 } 145 150 146 // Capture request-bound moderator, timestamp and deleted-comment data now. 147 if ( in_array( $current_action, array( 'transition_comment_status', 'spammed_comment', 'deleted_comment' ), true ) ) { 151 // Cart events are tracked only for authenticated customers. 152 if ( 'woocommerce_add_to_cart' === $current_action && ! is_user_logged_in() ) { 153 return; 154 } 155 156 // Capture request-bound moderation and cart data before the event enters the queue. 157 if ( in_array( $current_action, array( 'transition_comment_status', 'spammed_comment', 'deleted_comment', 'woocommerce_add_to_cart', 'woocommerce_order_refunded' ), true ) ) { 148 158 $args = $this->normalize_hook_arguments( $current_action, $args ); 149 159 } … … 300 310 } 301 311 302 $timestamp = current_time( 'mysql');312 $timestamp = date('Y-m-d H:i:s'); 303 313 if ( is_callable( array( $submission, 'get_meta' ) ) ) { 304 314 $submitted_at = $submission->get_meta( 'timestamp' ); … … 611 621 $already_normalized && isset( $args[3] ) 612 622 ? sanitize_text_field( (string) $args[3] ) 613 : gmdate( 'Y-m-d\TH:i:s\Z' ),623 : current_time( 'mysql' ), 614 624 ); 625 626 case 'woocommerce_add_to_cart': 627 if ( isset( $args[0] ) && is_array( $args[0] ) && isset( $args[0]['products'] ) ) { 628 return array( $this->normalize_queue_value( $args[0] ) ); 629 } 630 631 $payload = $this->build_add_to_cart_payload( $args ); 632 return empty( $payload ) ? array() : array( $payload ); 633 634 case 'woocommerce_order_refunded': 635 if ( isset( $args[0] ) && is_array( $args[0] ) && isset( $args[0]['refund_id'] ) ) { 636 return array( $this->normalize_queue_value( $args[0] ) ); 637 } 638 639 $payload = $this->build_refunded_order_payload( $args ); 640 return empty( $payload ) ? array() : array( $payload ); 615 641 616 642 case 'deleted_comment': … … 661 687 'comment_text' => $content, 662 688 'comment_length' => $length, 663 'timestamp' => gmdate( 'Y-m-d\TH:i:s\Z' ),689 'timestamp' => current_time( 'mysql' ), 664 690 ), 665 691 ); … … 667 693 668 694 return $this->normalize_queue_value( $args ); 695 } 696 697 /** 698 * Captures the complete cart state while the WooCommerce request is active. 699 * 700 * @param array $args Raw woocommerce_add_to_cart hook arguments. 701 * @return array 702 */ 703 private function build_add_to_cart_payload( array $args ) { 704 $woocommerce = function_exists( 'WC' ) ? WC() : null; 705 if ( ! $woocommerce || ! $woocommerce->cart ) { 706 return array(); 707 } 708 709 $cart_items = $woocommerce->cart->get_cart(); 710 $products = array(); 711 $included_categories = array(); 712 $cart_total_price = 0.0; 713 714 foreach ( $cart_items as $cart_item ) { 715 if ( ! is_array( $cart_item ) ) { 716 continue; 717 } 718 719 $product_id = isset( $cart_item['product_id'] ) ? absint( $cart_item['product_id'] ) : 0; 720 $quantity = isset( $cart_item['quantity'] ) ? max( 0, (float) $cart_item['quantity'] ) : 0.0; 721 if ( ! $product_id ) { 722 continue; 723 } 724 725 $products[] = $product_id; 726 727 $term_ids = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'ids' ) ); 728 if ( ! is_wp_error( $term_ids ) ) { 729 $included_categories = array_merge( $included_categories, array_map( 'absint', $term_ids ) ); 730 } 731 732 $product = isset( $cart_item['data'] ) && is_object( $cart_item['data'] ) 733 ? $cart_item['data'] 734 : wc_get_product( $product_id ); 735 736 if ( $product && is_callable( array( $product, 'get_price' ) ) ) { 737 $cart_total_price += (float) $product->get_price() * $quantity; 738 } 739 } 740 741 $products = array_values( array_unique( array_filter( array_map( 'absint', $products ) ) ) ); 742 $included_categories = array_values( array_unique( array_filter( array_map( 'absint', $included_categories ) ) ) ); 743 744 if ( empty( $products ) ) { 745 $added_product_id = isset( $args[1] ) ? absint( $args[1] ) : 0; 746 if ( ! $added_product_id || ! wc_get_product( $added_product_id ) ) { 747 return array(); 748 } 749 $products[] = $added_product_id; 750 } 751 752 $user_id = get_current_user_id(); 753 $session_id = ''; 754 if ( $woocommerce->session && is_callable( array( $woocommerce->session, 'get_customer_id' ) ) ) { 755 $session_id = sanitize_text_field( (string) $woocommerce->session->get_customer_id() ); 756 } 757 758 $cart_item_key = isset( $args[0] ) ? sanitize_text_field( (string) $args[0] ) : ''; 759 $cart_id = is_callable( array( $woocommerce->cart, 'get_cart_hash' ) ) 760 ? sanitize_text_field( (string) $woocommerce->cart->get_cart_hash() ) 761 : $cart_item_key; 762 763 $payload = array( 764 'username' => $user_id ? (string) Philia_API_Settings::get_user_mobile( $user_id ) : '', 765 'timestamp' => date('Y-m-d H:i:s'), 766 'anonymous_id' => '', 767 'uid' => $user_id ? (string) $user_id : '', 768 'cart_id' => $cart_id ?: $cart_item_key, 769 'device_id' => $session_id, 770 'session_id' => $session_id, 771 'cart_total_price' => (float) $cart_total_price, 772 'currency' => function_exists( 'get_woocommerce_currency' ) ? (string) get_woocommerce_currency() : '', 773 'products' => $products, 774 'included_categories' => $included_categories, 775 'purchase_channel' => 'web', 776 'branch' => '', 777 ); 778 779 return $payload; 780 } 781 782 /** 783 * Captures a WooCommerce refund as a serializable event payload. 784 * 785 * @param array $args Raw woocommerce_order_refunded hook arguments. 786 * @return array 787 */ 788 private function build_refunded_order_payload( array $args ) { 789 $order_id = isset( $args[0] ) ? absint( $args[0] ) : 0; 790 $refund_id = isset( $args[1] ) ? absint( $args[1] ) : 0; 791 792 if ( ! $order_id || ! $refund_id || ! function_exists( 'wc_get_order' ) ) { 793 return array(); 794 } 795 796 $order = wc_get_order( $order_id ); 797 $refund = wc_get_order( $refund_id ); 798 if ( ! $order || ! $refund || ! is_a( $refund, 'WC_Order_Refund' ) ) { 799 return array(); 800 } 801 802 $user_id = absint( $order->get_customer_id() ); 803 $mobile = sanitize_text_field( (string) $order->get_billing_phone() ); 804 $mobile = (string) preg_replace( '/^(?:\+98|0098|98|0)/', '', $mobile ); 805 if ( '' === $mobile && $user_id ) { 806 $mobile = (string) Philia_API_Settings::get_user_mobile( $user_id ); 807 } 808 809 $products = array(); 810 foreach ( $refund->get_items( 'line_item' ) as $item ) { 811 if ( ! is_object( $item ) ) { 812 continue; 813 } 814 815 $variation_id = is_callable( array( $item, 'get_variation_id' ) ) ? absint( $item->get_variation_id() ) : 0; 816 $product_id = $variation_id ?: ( is_callable( array( $item, 'get_product_id' ) ) ? absint( $item->get_product_id() ) : 0 ); 817 $quantity = is_callable( array( $item, 'get_quantity' ) ) ? abs( (float) $item->get_quantity() ) : 0; 818 if ( ! $product_id || 0 >= $quantity ) { 819 continue; 820 } 821 822 $products[] = array( 823 'id' => (string) $product_id, 824 'quantity' => floor( $quantity ) === $quantity ? (int) $quantity : $quantity, 825 ); 826 } 827 828 $created_at = $refund->get_date_created(); 829 $timestamp = $created_at && is_callable( array( $created_at, 'date' ) ) 830 ? $created_at->date( 'Y-m-d H:i:s' ) 831 : current_time( 'mysql' ); 832 833 $anonymous_id = (string) apply_filters( 'philia_refunded_order_anonymous_id', '', $order, $refund ); 834 $refund_channel = (string) apply_filters( 'philia_refunded_order_channel', '', $order, $refund ); 835 836 $payload = array( 837 'username' => $mobile, 838 'first_name' => sanitize_text_field( (string) $order->get_billing_first_name() ), 839 'last_name' => sanitize_text_field( (string) $order->get_billing_last_name() ), 840 'mobile' => $mobile, 841 'email' => sanitize_email( (string) $order->get_billing_email() ), 842 'timestamp' => $timestamp, 843 'order_id' => $order_id, 844 'refund_id' => $refund_id, 845 'anonymous_id' => sanitize_text_field( $anonymous_id ), 846 'uid' => $user_id, 847 'currency' => sanitize_text_field( (string) $order->get_currency() ), 848 'refund_total_price' => abs( (float) $refund->get_amount() ), 849 'refund_reason' => sanitize_textarea_field( (string) $refund->get_reason() ), 850 'refund_channel' => sanitize_text_field( $refund_channel ), 851 'products' => $products, 852 ); 853 854 return (array) apply_filters( 'philia_refunded_order_payload', $payload, $order, $refund ); 669 855 } 670 856 … … 712 898 private function send_event( $current_action, array $args ) { 713 899 if ( empty( $this->app_secret ) ) { 900 return; 901 } 902 903 // Re-check at dispatch time so disabling refund sync also cancels queued refund events. 904 if ( 905 'woocommerce_order_refunded' === $current_action 906 && ! Philia_API_Settings::is_philia_data_sync_enabled( '6' ) 907 ) { 714 908 return; 715 909 } … … 847 1041 848 1042 $view_payload = array( 849 'timestamp' => $timestamp ?: current_time( 'mysql'),1043 'timestamp' => $timestamp ?: date('Y-m-d H:i:s'), 850 1044 'action' => 'view', 851 1045 'object_type' => 'view', … … 959 1153 960 1154 $deleted_payload = array( 961 'timestamp' => isset( $deleted['timestamp'] ) ? sanitize_text_field( (string) $deleted['timestamp'] ) : gmdate( 'Y-m-d\TH:i:s\Z'),1155 'timestamp' => isset( $deleted['timestamp'] ) ? sanitize_text_field( (string) $deleted['timestamp'] ) : date('Y-m-d H:i:s'), 962 1156 'action' => 'delete', 963 1157 'object_type' => 'comment', … … 1007 1201 'target_type' => $target_type, 1008 1202 'target_id' => $target_type . '_' . absint( $comment->comment_post_ID ), 1009 'timestamp' => $timestamp ?: current_time( 'mysql'),1203 'timestamp' => $timestamp ?: date('Y-m-d H:i:s'), 1010 1204 ); 1011 1205 … … 1038 1232 'object_type' => 'comment', 1039 1233 'object_id' => 'comment_' . $comment_id, 1040 'timestamp' => $timestamp ?: gmdate( 'Y-m-d\TH:i:s\Z'),1234 'timestamp' => $timestamp ?: date('Y-m-d H:i:s'), 1041 1235 ); 1042 1236 if ( $moderator_id ) { … … 1051 1245 1052 1246 case 'woocommerce_add_to_cart': 1053 if ( ! is_user_logged_in() ) { 1054 return array(); 1055 } 1056 1057 $product_id = isset( $args[1] ) ? absint( $args[1] ) : 0; 1058 if ( $product_id && class_exists( 'WC_Product' ) && wc_get_product( $product_id ) ) { 1247 $payload = isset( $args[0] ) && is_array( $args[0] ) ? $args[0] : array(); 1248 if ( ! empty( $payload ) && isset( $payload['products'] ) ) { 1059 1249 $data = array( 1060 'product_id' => $product_id, 1061 'quantity' => isset( $args[2] ) ? absint( $args[2] ) : 0, 1062 'variation_id' => isset( $args[3] ) ? absint( $args[3] ) : 0, 1250 'event_id' => self::ADD_TO_CART_EVENT_ID, 1251 'payload' => $payload, 1252 ); 1253 } 1254 break; 1255 1256 case 'woocommerce_order_refunded': 1257 $payload = isset( $args[0] ) && is_array( $args[0] ) ? $args[0] : array(); 1258 if ( ! empty( $payload ) && ! empty( $payload['order_id'] ) && ! empty( $payload['refund_id'] ) ) { 1259 $data = array( 1260 'event_id' => self::REFUNDED_ORDER_EVENT_ID, 1261 'payload' => $payload, 1063 1262 ); 1064 1263 } -
philia-integration/trunk/includes/class-login-redirect.php
r3683158 r3720581 1 1 <?php 2 2 /** 3 * PhiliaLogin Redirect4 * Manages user login to Philiausing redirect from WooCommerce user account.3 * Legion Login Redirect 4 * Manages user login to Legion using redirect from WooCommerce user account. 5 5 * 6 * Package: Philia7 * Author: Philia6 * Package: Legion 7 * Author: Legion 8 8 */ 9 9 -
philia-integration/trunk/includes/class-philia-referral.php
r3693436 r3720581 1 1 <?php 2 2 /** 3 * PhiliaReferral System3 * Legion Referral System 4 4 * Manages referral tracking and user registration with referral codes. 5 5 * 6 * Package: Philia7 * Author: Philia6 * Package: Legion 7 * Author: Legion 8 8 */ 9 9 -
philia-integration/trunk/includes/class-philia-wallet.php
r3683431 r3720581 1 1 <?php 2 2 /** 3 * PhiliaWallet4 * Manages Philiacashback wallet integration on the WooCommerce checkout page.3 * Legion Wallet 4 * Manages Legion cashback wallet integration on the WooCommerce checkout page. 5 5 * 6 * Package: Philia7 * Author: Philia6 * Package: Legion 7 * Author: Legion 8 8 */ 9 9 … … 46 46 47 47 /** 48 * Translatable label used both as the order's payment-method title 49 * and as the name of the wallet fee line (kept in sync so detection 50 * logic in get_wallet_amount_for_order() always matches). 48 * Display label used as the order's payment-method title and wallet fee name. 51 49 * 52 50 * @return string 53 51 */ 54 52 public static function get_payment_method_title() { 55 return __( 'Philia Wallet', 'philia-integration' ); 53 if ( class_exists( 'Philia_API\Philia_API_Settings' ) ) { 54 return Philia_API_Settings::get_wallet_title(); 55 } 56 57 return __('Legion Wallet', 'philia-integration'); 56 58 } 57 59 … … 175 177 */ 176 178 public function fetch_balance( $phone ) { 177 $result = [];178 179 179 $response = Philia_Core_API::send_request('integration/cashback/user/balance/?phone_number=' . urlencode( $phone ), 'GET', []); 180 180 181 if ( is_wp_error( $response ) ) {181 if ( is_wp_error( $response ) || ! is_array( $response ) ) { 182 182 error_log("Error in 'integration/cashback/user/balance/' for get user wallet balance"); 183 $result = [ 'user_cashback' => 0, 'currency' => $this->get_currency_symbol() ]; 184 return $result; 185 } 186 187 $result = [ 'user_cashback' => json_decode( wp_remote_retrieve_body( $response ), true )['data']['user_cashback'], 'currency' => $this->get_currency_symbol() ]; 188 189 return $result; 183 return false; 184 } 185 186 $status_code = (int) wp_remote_retrieve_response_code( $response ); 187 $response_body = json_decode( wp_remote_retrieve_body( $response ), true ); 188 if ( 189 $status_code < 200 190 || $status_code >= 300 191 || ! is_array( $response_body ) 192 || empty( $response_body['success'] ) 193 || ! isset( $response_body['data'] ) 194 || ! is_array( $response_body['data'] ) 195 || ! isset( $response_body['data']['user_cashback'] ) 196 ) { 197 error_log( "Philia wallet balance request failed with HTTP status {$status_code}." ); 198 return false; 199 } 200 201 return array( 202 'user_cashback' => (float) $response_body['data']['user_cashback'], 203 'is_active' => isset( $response_body['data']['is_active'] ) 204 ? filter_var( $response_body['data']['is_active'], FILTER_VALIDATE_BOOLEAN ) 205 : false, 206 'currency' => $this->get_currency_symbol(), 207 ); 190 208 } 191 209 … … 211 229 $response = Philia_Core_API::send_request( 'integration/cashback/user/balance/adjust/', 'POST', $body ); 212 230 213 if ( is_wp_error( $response ) ) {231 if ( is_wp_error( $response ) || ! is_array( $response ) ) { 214 232 error_log("Error in 'integration/cashback/user/balance/adjust/' for adjust user wallet balance"); 215 233 return false; 216 234 } 217 235 218 return json_decode( wp_remote_retrieve_body( $response ), true ); 236 $status_code = (int) wp_remote_retrieve_response_code( $response ); 237 $response_body = json_decode( wp_remote_retrieve_body( $response ), true ); 238 if ( 239 $status_code < 200 240 || $status_code >= 300 241 || ! is_array( $response_body ) 242 || empty( $response_body['success'] ) 243 ) { 244 error_log( "Philia wallet balance adjustment failed with HTTP status {$status_code}." ); 245 return false; 246 } 247 248 return $response_body; 219 249 } 220 250 … … 244 274 } 245 275 276 $woocommerce = self::get_woocommerce_instance(); 277 $data['wallet_active'] = (bool) ( 278 $woocommerce 279 && $woocommerce->session 280 && $woocommerce->session->get( self::SESSION_ACTIVE, false ) 281 ); 282 246 283 wp_send_json_success( $data ); 247 284 } … … 250 287 * AJAX: Toggle wallet usage on / off. 251 288 * 252 * ON (checked=true) → action=' add'+ add negative fee → update_checkout253 * OFF (checked=false) → action=' decrease'+ remove fee → update_checkout289 * ON (checked=true) → action='decrease' + add negative fee → update_checkout 290 * OFF (checked=false) → action='add' + remove fee → update_checkout 254 291 */ 255 292 public function ajax_toggle_wallet() { … … 265 302 ); 266 303 } 267 268 $user_id = get_current_user_id(); 269 $enabled = filter_var( $_POST['checked'] ?? 'false', FILTER_VALIDATE_BOOLEAN ); 270 $phone = $this->get_user_phone( $user_id ); 271 272 $prev_active = $woocommerce->session->get( self::SESSION_ACTIVE, false ); 304 305 $user_id = get_current_user_id(); 306 $enabled = filter_var( $_POST['checked'] ?? 'false', FILTER_VALIDATE_BOOLEAN ); 307 $phone = $this->get_user_phone( $user_id ); 308 $prev_active = (bool) $woocommerce->session->get( self::SESSION_ACTIVE, false ); 273 309 $prev_amount = floatval( $woocommerce->session->get( self::SESSION_AMOUNT, 0 ) ); 310 311 if ( ! $user_id || empty( $phone ) ) { 312 wp_send_json_error( 313 array( 314 'code' => 'no_phone', 315 'message' => __( 'A valid phone number is required to use the wallet.', 'philia-integration' ), 316 'wallet_active' => $prev_active, 317 ) 318 ); 319 } 274 320 275 321 if ( $enabled ) { … … 281 327 if ( class_exists( 'Philia_API\Philia_API_Settings' ) && ! Philia_API_Settings::is_wallet_enabled_for_gateway( $chosen_gateway ) ) { 282 328 if ( $prev_active && $prev_amount > 0 ) { 283 $this->adjust_balance( $phone, $prev_amount, 'add', $user_id, 'Checkout Gateway Restriction' ); 329 $adjusted = $this->adjust_balance( $phone, $prev_amount, 'add', $user_id, 'Checkout Gateway Restriction' ); 330 if ( false === $adjusted ) { 331 wp_send_json_error( 332 array( 333 'code' => 'wallet_refund_failed', 334 'message' => __( 'The wallet credit could not be restored. Wallet usage remains active.', 'philia-integration' ), 335 'wallet_active' => true, 336 ) 337 ); 338 } 284 339 } 285 340 286 341 $woocommerce->session->set( self::SESSION_ACTIVE, false ); 287 342 $woocommerce->session->set( self::SESSION_AMOUNT, 0 ); 343 $woocommerce->cart->calculate_fees(); 344 288 345 wp_send_json_error( 289 346 array( 290 'message' => __( 'Philia wallet is not enabled for the selected payment method.', 'philia-integration' ), 347 'code' => 'gateway_not_allowed', 348 'message' => __( 'Legion wallet is not enabled for the selected payment method.', 'philia-integration' ), 349 'wallet_active' => false, 291 350 ) 292 351 ); 293 352 } 294 353 295 // Activate : deduct the amount from the wallet and store it in the cart session.354 // Activate only after the cashback service and balance adjustment both succeed. 296 355 $balance_data = $this->fetch_balance( $phone ); 297 $balance = isset( $balance_data['user_cashback'] ) ? floatval( $balance_data['user_cashback'] ) : 0; 298 356 if ( false === $balance_data ) { 357 wp_send_json_error( 358 array( 359 'code' => 'balance_unavailable', 360 'message' => __( 'The wallet balance could not be retrieved.', 'philia-integration' ), 361 'wallet_active' => $prev_active, 362 ) 363 ); 364 } 365 366 if ( empty( $balance_data['is_active'] ) ) { 367 wp_send_json_error( 368 array( 369 'code' => 'cashback_inactive', 370 'message' => __( 'Cashback is currently inactive.', 'philia-integration' ), 371 'wallet_active' => $prev_active, 372 'cashback_active' => false, 373 ) 374 ); 375 } 376 377 $balance = isset( $balance_data['user_cashback'] ) ? floatval( $balance_data['user_cashback'] ) : 0; 378 299 379 // Calculate the cart total without the current wallet discount. 300 380 $current_total = floatval( $woocommerce->cart->get_total('edit') ); 301 381 $wallet_to_use = min( $balance, $current_total + $prev_amount ); 302 382 303 if ( $wallet_to_use > 0 ) { 304 $this->adjust_balance( $phone, $wallet_to_use, 'decrease', $user_id, 'Checkout Activation' ); 305 $woocommerce->session->set( self::SESSION_ACTIVE, true ); 306 $woocommerce->session->set( self::SESSION_AMOUNT, $wallet_to_use ); 307 } 383 if ( $wallet_to_use <= 0 ) { 384 wp_send_json_error( 385 array( 386 'code' => 'insufficient_wallet_balance', 387 'message' => __( 'There is no wallet balance available to use.', 'philia-integration' ), 388 'wallet_active' => $prev_active, 389 'cashback_active' => true, 390 ) 391 ); 392 } 393 394 $adjusted = $this->adjust_balance( $phone, $wallet_to_use, 'decrease', $user_id, 'Checkout Activation' ); 395 if ( false === $adjusted ) { 396 wp_send_json_error( 397 array( 398 'code' => 'wallet_decrease_failed', 399 'message' => __( 'The wallet balance could not be deducted.', 'philia-integration' ), 400 'wallet_active' => $prev_active, 401 'cashback_active' => true, 402 ) 403 ); 404 } 405 406 $woocommerce->session->set( self::SESSION_ACTIVE, true ); 407 $woocommerce->session->set( self::SESSION_AMOUNT, $wallet_to_use ); 308 408 } else { 309 // Deactivate : return the amount to the wallet and clear the session.409 // Deactivate only after the reserved amount is restored successfully. 310 410 if ( $prev_active && $prev_amount > 0 ) { 311 $this->adjust_balance( $phone, $prev_amount, 'add', $user_id, 'Checkout Deactivation' ); 312 } 411 $adjusted = $this->adjust_balance( $phone, $prev_amount, 'add', $user_id, 'Checkout Deactivation' ); 412 if ( false === $adjusted ) { 413 wp_send_json_error( 414 array( 415 'code' => 'wallet_refund_failed', 416 'message' => __( 'The wallet credit could not be restored. Wallet usage remains active.', 'philia-integration' ), 417 'wallet_active' => true, 418 ) 419 ); 420 } 421 } 422 313 423 $woocommerce->session->set( self::SESSION_ACTIVE, false ); 314 424 $woocommerce->session->set( self::SESSION_AMOUNT, 0 ); … … 316 426 317 427 $woocommerce->cart->calculate_fees(); 318 wp_send_json_success(); 428 wp_send_json_success( 429 array( 430 'wallet_active' => (bool) $woocommerce->session->get( self::SESSION_ACTIVE, false ), 431 ) 432 ); 319 433 } 320 434 … … 341 455 if ( $active && $amount > 0 ) { 342 456 $cart->add_fee( 343 __( 'Philia Wallet', 'philia-integration'),457 self::get_payment_method_title(), 344 458 -$amount, 345 459 false // not taxable … … 425 539 $order->payment_complete(); 426 540 $order->add_order_note( 427 __( 'The order was fully paid using the Philiawallet.', 'philia-integration' )541 __( 'The order was fully paid using the Legion wallet.', 'philia-integration' ) 428 542 ); 429 543 } … … 457 571 } 458 572 459 $ this->adjust_balance(573 $adjusted = $this->adjust_balance( 460 574 $phone, 461 575 $wallet_amount, … … 468 582 ) 469 583 ); 584 585 if ( false === $adjusted ) { 586 $order->add_order_note( 587 __( 'Legion wallet credit could not be restored because the cashback service rejected the request.', 'philia-integration' ) 588 ); 589 error_log( "Philia wallet refund failed for cancelled order ID {$order_id}." ); 590 } 470 591 } 471 592 … … 523 644 // ── 2. Philia wallet fee line fallback ─────────────────────────────── 524 645 $philia_fee = 0.0; 646 $recognized_fee_titles = array( 647 self::get_payment_method_title(), 648 __( 'Legion Wallet', 'philia-integration' ), 649 ); 525 650 foreach ( $order->get_items( 'fee' ) as $fee_item ) { 526 651 /** @var \WC_Order_Item_Fee $fee_item */ 527 if ( $fee_item->get_name() === self::get_payment_method_title() ) {652 if ( in_array( $fee_item->get_name(), $recognized_fee_titles, true ) ) { 528 653 $philia_fee += abs( (float) $fee_item->get_total() ); 529 654 } … … 571 696 $this->enqueue_wallet_script(); 572 697 573 $atts = shortcode_atts( [ 'title' => '' ], $atts, 'philia-wallet' ); 574 $title = esc_html( $atts['title'] ); 698 $atts = shortcode_atts( [ 'title' => '' ], $atts, 'philia-wallet' ); 699 $shortcode_title = trim( sanitize_text_field( $atts['title'] ) ); 700 $title = esc_html( $shortcode_title !== '' ? $shortcode_title : self::get_payment_method_title() ); 575 701 576 702 ob_start(); -
philia-integration/trunk/includes/class-webhook-sender.php
r3683158 r3720581 1 1 <?php 2 2 /** 3 * PhiliaWebhook Sender3 * Legion Webhook Sender 4 4 * The class responsible for sending webhook notifications for various WordPress/WooCommerce events. 5 5 * 6 * Package: Philia7 * Author: Philia6 * Package: Legion 7 * Author: Legion 8 8 */ 9 9 … … 936 936 $order = wc_get_order($order_id); 937 937 if ($order) { 938 // Get the configured order status for synchronization (default: 'completed') 938 // Get the configured order status for synchronization (default: 'completed'). 939 939 $settings_class = __NAMESPACE__ . '\\Philia_API_Settings'; 940 940 $sync_status = ( class_exists( $settings_class ) && is_callable( array( $settings_class, 'get_order_sync_status' ) ) ) 941 941 ? call_user_func( array( $settings_class, 'get_order_sync_status' ) ) 942 942 : 'completed'; 943 944 // ONLY proceed if the order status matches the configured sync status 945 if ($order->get_status() !== $sync_status) { 946 error_log("Philia_Webhook_Sender: Order ID {$order_id} status is '{$order->get_status()}', not '{$sync_status}'. Skipping webhook send."); 943 $order_status = $order->get_status(); 944 945 // ONLY proceed if the order has the configured synchronization status. 946 if ( $order_status !== $sync_status ) { 947 error_log( "Philia_Webhook_Sender: Order ID {$order_id} status is '{$order_status}', not the configured status '{$sync_status}'. Skipping webhook send." ); 947 948 return []; // Return empty data to prevent sending webhook 948 949 } … … 1201 1202 array( 1202 1203 'id' => '_philia_product_id', 1203 'label' => __( ' PhiliaProduct ID', 'philia-integration' ),1204 'label' => __( 'Legion Product ID', 'philia-integration' ), 1204 1205 'desc_tip' => true, 1205 'description' => __( 'This ID is used for syncing with the philiaclub.', 'philia-integration' ),1206 'description' => __( 'This ID is used for syncing with the legion club.', 'philia-integration' ), 1206 1207 'value' => get_post_meta( $post->ID, '_philia_product_id', true ), 1207 1208 ) … … 1219 1220 'name' => '_philia_product_id[' . $variation->ID . ']', 1220 1221 'value' => get_post_meta( $variation->ID, '_philia_product_id', true ), 1221 'label' => __( ' PhiliaProduct ID', 'philia-integration' ),1222 'label' => __( 'Legion Product ID', 'philia-integration' ), 1222 1223 'desc_tip' => true, 1223 'description' => __( 'Enter the PhiliaProduct ID for this variation.', 'philia-integration' ),1224 'description' => __( 'Enter the Legion Product ID for this variation.', 'philia-integration' ), 1224 1225 'wrapper_class' => 'form-row form-row-full', 1225 1226 ) ); -
philia-integration/trunk/includes/templates/philia-wallet-payment.php
r3683431 r3720581 15 15 16 16 $philia_wallet_allowed = true; 17 $philia_wallet_title = __( 'Legion Wallet', 'philia-integration' ); 17 18 if ( class_exists( 'Philia_API\Philia_API_Settings' ) ) { 19 $philia_wallet_title = \Philia_API\Philia_API_Settings::get_wallet_title(); 18 20 $philia_chosen_gateway = $philia_session ? $philia_session->get( 'chosen_payment_method' ) : ''; 19 21 if ( ! empty( $philia_chosen_gateway ) ) { … … 31 33 </span> 32 34 <div class="philia-wallet-text"> 33 <span class="philia-wallet-label"><?php esc_html_e( 'Pay with Philia Wallet', 'philia-integration' ); ?></span> 35 <span class="philia-wallet-label"> 36 <?php 37 /* translators: %s: configured wallet title. */ 38 printf( esc_html__( 'Pay with %s', 'philia-integration' ), esc_html( $philia_wallet_title ) ); 39 ?> 40 </span> 34 41 <span class="philia-wallet-balance-wrap">(<?php esc_html_e( 'Balance:', 'philia-integration' ); ?> <span class="philia-wallet-balance"><?php esc_html_e( 'Loading...', 'philia-integration' ); ?></span>)</span> 35 42 </div> -
philia-integration/trunk/philia-integration.php
r3693436 r3720581 1 1 <?php 2 2 /** 3 * Plugin Name: PhiliaIntegration with WooCommerce4 * Description: Sending Users, Products, Categories and invoices from WooCommerce to Philia and Receive Coupons and Cashback from Philia5 * Version: 1.1 8.26 * Author: Philia7 * Author URI: https:// fa.philia.vip3 * Plugin Name: Legion Integration with WooCommerce 4 * Description: Sending Users, Products, Categories and invoices from WooCommerce to Legion and Receive Coupons and Cashback from Legion 5 * Version: 1.19 6 * Author: Legion 7 * Author URI: https://legion.tools 8 8 * License: GPL-2.0+ 9 9 * License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 17 17 18 18 // Define constants for plugin directory, URL, and table prefix. 19 define('PHILIA_PLUGIN_VERSION', '1.1 8.2');19 define('PHILIA_PLUGIN_VERSION', '1.19'); 20 20 define('PHILIA_PLUGIN_DIR', plugin_dir_path(__FILE__)); 21 21 define('PHILIA_PLUGIN_URL', plugin_dir_url(__FILE__)); … … 44 44 function philia_api_add_menu_page() { 45 45 add_menu_page( 46 __(' PhiliaAPI Settings', 'philia-integration'), // Page title47 __(' Philia', 'philia-integration'), // Menu title46 __('Legion API Settings', 'philia-integration'), // Page title 47 __('Legion', 'philia-integration'), // Menu title 48 48 'manage_options', // Capability 49 49 'philia-api-settings', // Menu slug -
philia-integration/trunk/readme.txt
r3693436 r3720581 1 === PhiliaIntegration with WooCommerce ===1 === Legion Integration with WooCommerce === 2 2 Contributors: philiasolutions 3 3 Tags: philia, loyalty program, events & attributes 4 4 Requires at least: 6.0 5 5 Tested up to: 7.1 6 Stable tag: 1.1 8.26 Stable tag: 1.19 7 7 License: GPL-2.0+ 8 8 License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 9 10 Send Users, Products, Categories and invoices from WooCommerce to Philia and Receive Coupons and Cashback from Philia10 Send Users, Products, Categories and invoices from WooCommerce to Legion and Receive Coupons and Cashback from Legion 11 11 12 12 == Description == 13 13 14 Philia Sync Plugin For WooCommerce is a product developed by the <a href="https://fa.philia.vip">Philia</a> company. Philia is a Customer Loyalty Program platform that offers services such as Defining Loyalty Roadmaps and programs for each business, in any industry and more. This plugin is a sync and integration solution for sending trackable data to philia for progressing loyalty missions, sending required events and etc within the WooCommerce platform. Using this plugin, businesses can integrate their WooCommerce store with Philia.15 This plugin automatically transfers users, products, categories, orders and other required events. It also uses WooWallet plugin to integrate philia's cashback to WooCommerce.16 It's important to note that the plugin connects to philia via a web service, and we have designed this web service to be secure. We attach great importance to user rights and data, and we recommend that you read the <a href="https://philia.vip/terms-of-service/" target="_blank">Terms of Service</a> of philiaand our plugin.14 Legion Sync Plugin For WooCommerce is a product developed by the <a href="https://legion.tools">Legion</a> company. Legion is a Customer Loyalty Program platform that offers services such as Defining Loyalty Roadmaps and programs for each business, in any industry and more. This plugin is a sync and integration solution for sending trackable data to legion for progressing loyalty missions, sending required events and etc within the WooCommerce platform. Using this plugin, businesses can integrate their WooCommerce store with Legion. 15 This plugin automatically transfers users, products, categories, orders and other required events. It also uses WooWallet plugin to integrate legion's cashback to WooCommerce. 16 It's important to note that the plugin connects to legion via a web service, and we have designed this web service to be secure. We attach great importance to user rights and data, and we recommend that you read the <a href="https://legion.tools/terms-of-service/" target="_blank">Terms of Service</a> of legion and our plugin. 17 17 18 18 Key features of the plugin: 19 19 20 - Integrate WooCommerce users and Philia21 - Integrate WooCommerce products and Philia22 - Integrate WooCommerce categories and Philia23 - Integrate WooCommerce orders and Philia24 - Integrate PhiliaCoupon Codes and WooCommerce25 - Integrate PhiliaWallet (Cashback)20 - Integrate WooCommerce users and Legion 21 - Integrate WooCommerce products and Legion 22 - Integrate WooCommerce categories and Legion 23 - Integrate WooCommerce orders and Legion 24 - Integrate Legion Coupon Codes and WooCommerce 25 - Integrate Legion Wallet (Cashback) 26 26 27 27 == Installation == … … 34 34 = This plugin is free = 35 35 36 Yes, the PhiliaIntegration is a free plugin.36 Yes, the Legion Integration is a free plugin. 37 37 38 38 = Is this plugin compatible with WooCommerce? = … … 42 42 = How does this plugin work? = 43 43 44 You first need to purchase the one of PhiliaSubscription plans. Then, you need to obtain the web service key and enter it in the plugin settings section of the WooCommerce configuration. Once this is done, the plugin will be connected to the your philia panel.44 You first need to purchase the one of Legion Subscription plans. Then, you need to obtain the web service key and enter it in the plugin settings section of the WooCommerce configuration. Once this is done, the plugin will be connected to the your philia panel. 45 45 46 46 == Changelog == 47 48 = 1.19 = 49 * Rebrand and change name to Legion 50 * Added Refund order to Data Synchronization 51 * Bugs fixes and improvements 47 52 48 53 = 1.18.2 = … … 68 73 = 1.16 = 69 74 * Compatible with WP 7 70 * Added PhiliaWallet & Cashback75 * Added Legion Wallet & Cashback 71 76 * Bugs fixes and improvements 72 77 … … 76 81 77 82 = 1.14 = 78 * Added Fill mode field for PhiliaProduct ID83 * Added Fill mode field for Legion Product ID 79 84 * Bugs fixes and improvements 80 85 … … 86 91 87 92 = 1.12 = 88 * Added custom field for better syncing with philia93 * Added custom field for better syncing with legion 89 94 * Fixed login to club bug and optimize the speed of login 90 95 * Bugs fixes and improvements … … 101 106 102 107 = 1.10 = 103 * Added Selective data for syncing with philia108 * Added Selective data for syncing with legion 104 109 * Bugs fixes and improvements 105 110
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)