Plugin Directory

Changeset 3280001


Ignore:
Timestamp:
04/23/2025 01:28:43 PM (9 months ago)
Author:
finalpos
Message:

Release 1.2.0: new setup flow

Location:
finalpos
Files:
48 added
38 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • finalpos/trunk/includes/common-functions.php

    r3209444 r3280001  
    55}
    66
    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')));
     7class 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;
    11213    }
    12214}
    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  
    55Tags: Point of sale, POS, WooCommerce Point of Sale, WooCommerce POS, POS Plugin
    66Requires at least: 4.9
    7 Tested up to: 6.6
     7Tested up to: 6.7.2
    88Requires PHP: 7.0
    9 Stable tag: 1.1.5
     9Stable tag: 1.2.0
    1010License: GPLv2 or later
    1111License URI: http://www.gnu.org/licenses/gpl-2.0
     
    5252
    5353== Screenshots ==
    54 1. Launch the Final POS Wizard
    55 2. Log in or Sign up for Final POS
    56 2. Configure your sync terms
    57 3. Allow WooCommerce API Authentification
    58 4. You're all set!
     541. Install the WooCommerce extension on your Final Hub account
     552. Copy the authentication key from Final Hub
     563. Paste the authentication key in the Final POS plugin
     574. Configure your sync settings
     584. You are all set
    5959
    6060
    6161== Installation ==
    6262
    63 
    64 1. Upload the `final-pos` folder to your `/wp-content/plugins/` directory.
     631. Upload the `finalpos` folder to your `/wp-content/plugins/` directory.
    65642. Go to the **Plugins** page in WordPress and activate the Final POS plugin.
    66653. Follow the setup instructions to pair your store with Final POS.
     
    7372
    7473Service URL - Final POS Backend Service:
    75 https://services.finalpos.com/v1/api
     74https://dev.services.finalpos.com/v1/api
    7675
    7776Terms of Use:
     
    9493
    9594== Changelog ==
     95
     96= 1.2.0 =
     97* New setup flow
     98
    9699= 1.1.5 =
    97100* Changes in stock updates
Note: See TracChangeset for help on using the changeset viewer.