Changeset 3280001
- Timestamp:
- 04/23/2025 01:28:43 PM (9 months ago)
- Location:
- finalpos
- Files:
-
- 48 added
- 38 deleted
- 2 edited
-
assets/screenshot-1.jpg (deleted)
-
assets/screenshot-1.png (added)
-
assets/screenshot-2.jpg (deleted)
-
assets/screenshot-2.png (added)
-
assets/screenshot-3.jpg (deleted)
-
assets/screenshot-3.png (added)
-
assets/screenshot-4.jpg (deleted)
-
assets/screenshot-4.png (added)
-
assets/screenshot-5.jpg (deleted)
-
assets/screenshot-5.png (added)
-
trunk/assets/css/finalpos-common.css (added)
-
trunk/assets/css/finalpos-dashboard.css (added)
-
trunk/assets/css/finalpos-loader.css (added)
-
trunk/assets/css/finalpos-modals.css (added)
-
trunk/assets/css/finalpos-readonly-orders.css (added)
-
trunk/assets/css/finalpos-wizard.css (added)
-
trunk/assets/css/finalwizard.css (deleted)
-
trunk/assets/css/settings.css (deleted)
-
trunk/assets/css/ui (deleted)
-
trunk/assets/css/woo (deleted)
-
trunk/assets/img/auth-icon.svg (added)
-
trunk/assets/img/checkmark.svg (added)
-
trunk/assets/img/final-logo.svg (added)
-
trunk/assets/img/finalpos-icon.svg (added)
-
trunk/assets/img/icons (deleted)
-
trunk/assets/img/manage-hub-app.svg (added)
-
trunk/assets/img/manage-hub.svg (added)
-
trunk/assets/img/orders-customers-products.png (added)
-
trunk/assets/img/stores (added)
-
trunk/assets/img/stores/app-store-badge.svg (added)
-
trunk/assets/img/stores/google-play-badge.svg (added)
-
trunk/assets/img/stores/ms-store-badge.svg (added)
-
trunk/assets/img/sync-customers-icon.svg (added)
-
trunk/assets/img/sync-orders-icon.svg (added)
-
trunk/assets/img/sync-products-icon.svg (added)
-
trunk/assets/img/ui (deleted)
-
trunk/assets/img/wizard-step1.jpg (deleted)
-
trunk/assets/img/wizard-step3-legacy.jpg (deleted)
-
trunk/assets/img/wizard-step3-modern.jpg (deleted)
-
trunk/assets/img/woocommerce-sync.svg (added)
-
trunk/assets/js/dashboard-polling.js (added)
-
trunk/assets/js/finalwizard.js (deleted)
-
trunk/assets/js/lib (deleted)
-
trunk/assets/js/other (deleted)
-
trunk/assets/js/settings-form.js (added)
-
trunk/assets/js/ui (deleted)
-
trunk/assets/js/woo (deleted)
-
trunk/final-pos.php (deleted)
-
trunk/finalpos.php (added)
-
trunk/includes/admin/class-finalpos-admin-assets.php (added)
-
trunk/includes/admin/dashboard (added)
-
trunk/includes/admin/dashboard/class-finalpos-dashboard.php (added)
-
trunk/includes/admin/dashboard/views (added)
-
trunk/includes/admin/dashboard/views/dashboard-content.php (added)
-
trunk/includes/admin/finalwizard.php (deleted)
-
trunk/includes/admin/other (deleted)
-
trunk/includes/admin/save-wc-token.php (deleted)
-
trunk/includes/admin/ui (deleted)
-
trunk/includes/admin/wizard (added)
-
trunk/includes/admin/wizard/class-finalpos-wizard.php (added)
-
trunk/includes/admin/wizard/views (added)
-
trunk/includes/admin/wizard/views/activation-form.php (added)
-
trunk/includes/admin/wizard/views/orders-sync-modal.php (added)
-
trunk/includes/admin/wizard/views/products-sync-modal.php (added)
-
trunk/includes/admin/wizard/views/settings-form.php (added)
-
trunk/includes/ajax (added)
-
trunk/includes/ajax/save-wc-token.php (added)
-
trunk/includes/ajax/wc-api-handler.php (added)
-
trunk/includes/api (deleted)
-
trunk/includes/common-functions.php (modified) (1 diff)
-
trunk/includes/lifecycle.php (added)
-
trunk/integrations/klaviyo (deleted)
-
trunk/integrations/readonly-orders.php (added)
-
trunk/integrations/woo (deleted)
-
trunk/languages/final-pos-da_DK.mo (deleted)
-
trunk/languages/final-pos-da_DK.po (deleted)
-
trunk/languages/final-pos-de_DE.mo (deleted)
-
trunk/languages/final-pos-de_DE.po (deleted)
-
trunk/languages/final-pos-es_ES.mo (deleted)
-
trunk/languages/final-pos-es_ES.po (deleted)
-
trunk/languages/final-pos-fr_FR.mo (deleted)
-
trunk/languages/final-pos-fr_FR.po (deleted)
-
trunk/languages/final-pos-nb_NO.mo (deleted)
-
trunk/languages/final-pos-nb_NO.po (deleted)
-
trunk/languages/final-pos.pot (deleted)
-
trunk/languages/finalpos.pot (added)
-
trunk/readme.txt (modified) (4 diffs)
-
trunk/uninstall.php (added)
Legend:
- Unmodified
- Added
- Removed
-
finalpos/trunk/includes/common-functions.php
r3209444 r3280001 5 5 } 6 6 7 // Check if WooCommerce is active 8 if (!function_exists('final_is_woocommerce_active')) { 9 function final_is_woocommerce_active() { 10 return in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins'))); 7 class FinalPOS_Common { 8 /** 9 * Instance of the class 10 * 11 * @var FinalPOS_Common 12 */ 13 private static $instance = null; 14 15 /** 16 * Get the singleton instance 17 * 18 * @return FinalPOS_Common 19 */ 20 public static function get_instance() { 21 if (self::$instance === null) { 22 self::$instance = new self(); 23 } 24 return self::$instance; 25 } 26 27 /** 28 * Class constructor 29 */ 30 private function __construct() { 31 // Initialize if needed 32 } 33 34 /** 35 * Get parsed JWT data 36 * 37 * @param string $key Optional key to retrieve from parsed data 38 * @return mixed Parsed JWT data or specific key value 39 */ 40 public static function get_parsed_jwt_data($key = '') { 41 $parsed_jwt = get_option('finalpos_parsed_jwt'); 42 43 // If we don't have parsed JWT data but we have a token, parse it and store it 44 if ((!$parsed_jwt || !is_array($parsed_jwt)) && get_option('finalpos_jwt_token')) { 45 $parsed_jwt = self::parse_jwt_token(get_option('finalpos_jwt_token')); 46 47 if ($parsed_jwt) { 48 update_option('finalpos_parsed_jwt', $parsed_jwt); 49 } 50 } 51 52 if ($parsed_jwt && is_array($parsed_jwt)) { 53 if ($key && isset($parsed_jwt[$key])) { 54 return $parsed_jwt[$key]; 55 } 56 return $parsed_jwt; 57 } 58 59 return null; 60 } 61 62 /** 63 * Parse a JWT token into its component parts 64 * 65 * @param string $token JWT token 66 * @return array|null Parsed token data or null if invalid 67 */ 68 public static function parse_jwt_token($token) { 69 if (empty($token)) { 70 return null; 71 } 72 73 $jwt_parts = explode('.', $token); 74 if (count($jwt_parts) !== 3) { 75 return null; 76 } 77 78 // Decode payload 79 $payload = base64_decode(str_replace(['-', '_'], ['+', '/'], $jwt_parts[1])); 80 $decoded = json_decode($payload, true); 81 82 if ($decoded === null || !is_array($decoded)) { 83 return null; 84 } 85 86 return $decoded; 87 } 88 89 /** 90 * Get authorization headers with JWT token 91 * 92 * @param bool $include_content_type Whether to include Content-Type header 93 * @return array Headers with Authorization token 94 */ 95 public static function get_auth_headers($include_content_type = true) { 96 $jwt_token = get_option('finalpos_jwt_token'); 97 $headers = array('Authorization' => 'Bearer ' . $jwt_token); 98 99 if ($include_content_type) { 100 $headers['Content-Type'] = 'application/json'; 101 } 102 103 return $headers; 104 } 105 106 /** 107 * Make an API request to the Final POS API 108 * 109 * @param string $endpoint API endpoint (without base URL) 110 * @param string $method HTTP method (GET, POST, PUT, DELETE) 111 * @param array $data Data to send in the request body (for POST/PUT) 112 * @param array $headers Additional headers to include 113 * @param int $timeout Request timeout in seconds 114 * @return array Response data or WP_Error 115 */ 116 public static function api_request($endpoint, $method = 'GET', $data = null, $headers = array(), $timeout = 60) { 117 $url = rtrim(FINALPOS_API_BASE_URL, '/') . '/' . ltrim($endpoint, '/'); 118 119 $args = array( 120 'method' => strtoupper($method), 121 'headers' => $headers, 122 'timeout' => $timeout 123 ); 124 125 if ($data !== null && in_array(strtoupper($method), array('POST', 'PUT'))) { 126 $args['body'] = wp_json_encode($data); 127 } 128 129 $response = wp_remote_request($url, $args); 130 131 if (is_wp_error($response)) { 132 return $response; 133 } 134 135 $status_code = wp_remote_retrieve_response_code($response); 136 $body = wp_remote_retrieve_body($response); 137 138 if ($status_code >= 200 && $status_code < 300) { 139 // Try to decode JSON response 140 $decoded = json_decode($body, true); 141 return array( 142 'success' => true, 143 'status_code' => $status_code, 144 'body' => $decoded !== null ? $decoded : $body 145 ); 146 } 147 148 return array( 149 'success' => false, 150 'status_code' => $status_code, 151 'message' => wp_remote_retrieve_response_message($response), 152 'body' => $body 153 ); 154 } 155 156 /** 157 * Process API response error and redirect with error message 158 * 159 * @param mixed $response API response or WP_Error 160 * @param string $redirect_url URL to redirect to 161 * @param string $error_context Context for the error message 162 * @param array $request_details Additional request details for debugging 163 */ 164 public static function handle_api_error($response, $redirect_url, $error_context, $request_details = array()) { 165 if (is_wp_error($response)) { 166 $error_message = $response->get_error_message(); 167 $details = ''; 168 169 if (!empty($request_details)) { 170 $details = "\nRequest Details: " . print_r($request_details, true); 171 } 172 173 wp_redirect(add_query_arg('error', urlencode("$error_context: $error_message. $details"), $redirect_url)); 174 exit; 175 } 176 177 if (empty($response['success'])) { 178 $message = isset($response['message']) ? $response['message'] : 'Request failed.'; 179 $details = ''; 180 181 if (!empty($request_details)) { 182 $details = "\nRequest Details: " . print_r($request_details, true); 183 } 184 185 wp_redirect(add_query_arg('error', urlencode("$error_context: $message. $details"), $redirect_url)); 186 exit; 187 } 188 189 return true; 190 } 191 192 /** 193 * Update JWT token and its parsed data 194 * 195 * @param string $token JWT token 196 * @return bool Whether the update was successful 197 */ 198 public static function update_jwt_token($token) { 199 if (empty($token)) { 200 return false; 201 } 202 203 $parsed = self::parse_jwt_token($token); 204 205 if (!$parsed) { 206 return false; 207 } 208 209 update_option('finalpos_jwt_token', $token); 210 update_option('finalpos_parsed_jwt', $parsed); 211 212 return true; 11 213 } 12 214 } 13 14 /**15 * Retrieve user preferences for the current user.16 *17 * @return array User preferences.18 */19 function final_get_user_preferences() {20 return get_user_meta(get_current_user_id(), 'final_preferences', true) ?: [];21 }22 23 /**24 * Check if the current user has a specific role.25 *26 * @param string $role Role to check.27 * @return bool True if the user has the role, false otherwise.28 */29 function final_user_has_role($role) {30 return current_user_can($role);31 }32 33 /**34 * Get the latest content of a specified type.35 *36 * @param string $type Post type (default: 'post').37 * @param int $limit Number of posts to retrieve (default: 5).38 * @return array Array of latest content with title, author, date, edit link, and view link.39 */40 function final_get_latest_content($type = 'post', $limit = 5) {41 $args = [42 'post_type' => $type,43 'posts_per_page' => $limit,44 'orderby' => 'date',45 'order' => 'DESC',46 ];47 48 $latest_content = get_posts($args);49 50 return array_map(function ($item) {51 return [52 'title' => $item->post_title,53 'author' => get_the_author_meta('display_name', $item->post_author),54 'date' => get_the_date('Y-m-d', $item),55 'edit_link' => get_edit_post_link($item->ID),56 'view_link' => get_permalink($item->ID),57 ];58 }, $latest_content);59 }60 61 /**62 * Get the latest pages.63 *64 * @param int $limit Number of pages to retrieve (default: 5).65 * @return array Array of latest pages.66 */67 function final_get_latest_pages($limit = 5) {68 return final_get_latest_content('page', $limit);69 }70 71 /**72 * Get the latest posts.73 *74 * @param int $limit Number of posts to retrieve (default: 5).75 * @return array Array of latest posts.76 */77 function final_get_latest_posts($limit = 5) {78 return final_get_latest_content('post', $limit);79 }80 81 /**82 * Retrieve WooCommerce orders by status.83 *84 * @param string $status Order status.85 * @param int $limit Number of orders to retrieve (default: 10).86 * @return array Array of orders with details.87 */88 function final_get_woocommerce_orders_by_status($status, $limit = 10) {89 if (!final_is_woocommerce_active()) {90 return [];91 }92 93 $orders = wc_get_orders([94 'limit' => $limit,95 'status' => $status,96 'type' => 'shop_order',97 'orderby' => 'date',98 'order' => 'DESC',99 ]);100 101 return array_map(function($order) {102 if ($order instanceof WC_Order) {103 return [104 'id' => $order->get_id(),105 'number' => $order->get_order_number(),106 'customer' => $order->get_formatted_billing_full_name(),107 'total' => $order->get_total(),108 'date' => $order->get_date_created()->format('Y-m-d H:i:s'),109 ];110 }111 return null;112 }, $orders);113 }114 115 /**116 * Get the saved advanced settings for Final POS.117 *118 * @return array Saved advanced settings.119 */120 function final_get_advanced_settings() {121 return get_option('final_pos_advanced_settings', []);122 } -
finalpos/trunk/readme.txt
r3225806 r3280001 5 5 Tags: Point of sale, POS, WooCommerce Point of Sale, WooCommerce POS, POS Plugin 6 6 Requires at least: 4.9 7 Tested up to: 6. 67 Tested up to: 6.7.2 8 8 Requires PHP: 7.0 9 Stable tag: 1. 1.59 Stable tag: 1.2.0 10 10 License: GPLv2 or later 11 11 License URI: http://www.gnu.org/licenses/gpl-2.0 … … 52 52 53 53 == Screenshots == 54 1. Launch the Final POS Wizard55 2. Log in or Sign up for Final POS56 2. Configure your sync terms 57 3. Allow WooCommerce API Authentification 58 4. You 're all set!54 1. Install the WooCommerce extension on your Final Hub account 55 2. Copy the authentication key from Final Hub 56 3. Paste the authentication key in the Final POS plugin 57 4. Configure your sync settings 58 4. You are all set 59 59 60 60 61 61 == Installation == 62 62 63 64 1. Upload the `final-pos` folder to your `/wp-content/plugins/` directory. 63 1. Upload the `finalpos` folder to your `/wp-content/plugins/` directory. 65 64 2. Go to the **Plugins** page in WordPress and activate the Final POS plugin. 66 65 3. Follow the setup instructions to pair your store with Final POS. … … 73 72 74 73 Service URL - Final POS Backend Service: 75 https:// services.finalpos.com/v1/api74 https://dev.services.finalpos.com/v1/api 76 75 77 76 Terms of Use: … … 94 93 95 94 == Changelog == 95 96 = 1.2.0 = 97 * New setup flow 98 96 99 = 1.1.5 = 97 100 * Changes in stock updates
Note: See TracChangeset
for help on using the changeset viewer.