<?php if (!defined('ABSPATH')) { exit; } class Kara_WC_Order { public static function init() { /* * فعلاً ارسال خودکار را فعال نمی‌کنیم. * * از صفحه سفارش ووکامرس می‌توانیم سفارش را * به صورت دستی به کارا ارسال کنیم. */ add_action( 'woocommerce_admin_order_data_after_order_details', [__CLASS__, 'add_send_button'] ); add_action( 'admin_post_kara_send_order', [__CLASS__, 'send_order'] ); } /** * نمایش دکمه ارسال به کارا در صفحه سفارش */ public static function add_send_button($order) { if (!$order instanceof WC_Order) { return; } if (!current_user_can('manage_woocommerce')) { return; } $order_id = $order->get_id(); $url = wp_nonce_url( admin_url( 'admin-post.php?action=kara_send_order&order_id=' . $order_id ), 'kara_send_order_' . $order_id ); echo '<div style="margin-top:20px;padding:15px;border:1px solid #ddd;background:#fff;">'; echo '<h3>اتصال به کارا</h3>'; echo '<p>'; echo '<a href="' . esc_url($url) . '" class="button button-primary" onclick="return confirm(\'آیا سفارش به کارا ارسال شود؟\');" > ارسال سفارش به کارا </a>'; echo '</p>'; $result = $order->get_meta('_kara_last_response'); if (!empty($result)) { echo '<h4>آخرین پاسخ کارا</h4>'; echo '<textarea style="width:100%;min-height:250px;direction:ltr;font-family:monospace;" readonly >'; echo esc_textarea($result); echo '</textarea>'; } echo '</div>'; } /** * ارسال دستی سفارش */ public static function send_order() { if (!current_user_can('manage_woocommerce')) { wp_die( 'دسترسی کافی نیست.' ); } $order_id = isset($_GET['order_id']) ? absint($_GET['order_id']) : 0; if (!$order_id) { wp_die( 'شناسه سفارش مشخص نیست.' ); } check_admin_referer( 'kara_send_order_' . $order_id ); $order = wc_get_order($order_id); if (!$order) { wp_die( 'سفارش پیدا نشد.' ); } /* * تنظیمات کارا */ $settings = Kara_WC_API::settings(); $base_url = isset($settings['base_url']) ? trim($settings['base_url']) : ''; $username = isset($settings['username']) ? trim($settings['username']) : ''; $password = isset($settings['password']) ? trim($settings['password']) : ''; $version = isset($settings['version']) ? trim($settings['version']) : '2.4.17'; $warehouse_id = isset($settings['warehouse_id']) ? trim($settings['warehouse_id']) : ''; $settlement_type_id = isset($settings['settlement_type_id']) ? trim($settings['settlement_type_id']) : ''; $settlement_day = isset($settings['settlement_day']) ? trim($settings['settlement_day']) : '0'; if ( empty($base_url) || empty($username) || empty($password) ) { self::save_response( $order, array( 'success' => false, 'message' => 'تنظیمات اتصال کارا کامل نیست.' ) ); wp_safe_redirect( admin_url( 'post.php?post=' . $order_id . '&action=edit' ) ); exit; } /* * ------------------------------------------------- * 1. اطلاعات مشتری * ------------------------------------------------- */ $first_name = $order->get_billing_first_name(); $last_name = $order->get_billing_last_name(); $mobile = $order->get_billing_phone(); $phone = $order->get_billing_phone(); $province = $order->get_billing_state(); $city = $order->get_billing_city(); $address = $order->get_billing_address_1(); $address_2 = $order->get_billing_address_2(); $postcode = $order->get_billing_postcode(); $national_code = $order->get_meta('national_code'); /* * آدرس کامل: * استان + شهر + آدرس */ $full_address = implode( ' - ', array_filter( array( $province, $city, $address, $address_2 ) ) ); /* * گروه مشتری * * فعلاً از تنظیمات افزونه خوانده می‌شود. */ $group_code = isset($settings['group_code']) ? trim($settings['group_code']) : ''; /* * شناسه مشتری * * برای اینکه مشتری جدید دوباره ساخته نشود، * اول Partnerهای کارا را جستجو می‌کنیم. */ $partner = self::find_partner( $base_url, $username, $password, $version, $mobile ); /* * اگر مشتری پیدا نشد، فعلاً مشتری جدید می‌سازیم. */ if (!$partner) { $partner = self::create_partner( $base_url, $username, $password, $version, $first_name, $last_name, $mobile, $phone, $full_address, $postcode, $national_code, $group_code ); } if ( !$partner || empty($partner['PartnerId']) ) { self::save_response( $order, array( 'success' => false, 'stage' => 'partner', 'message' => 'شناسه مشتری در کارا پیدا/ایجاد نشد.', 'partner_response' => $partner ) ); wp_safe_redirect( admin_url( 'post.php?post=' . $order_id . '&action=edit' ) ); exit; } $partner_id = $partner['PartnerId']; /* * ------------------------------------------------- * 2. ساخت Articles * ------------------------------------------------- */ $articles = array(); foreach ($order->get_items() as $item) { $product = $item->get_product(); if (!$product) { continue; } /* * SKU = Code کارا */ $code = $product->get_sku(); if ($code === '') { continue; } $quantity = (float) $item->get_quantity(); /* * قیمت واقعی فروش سایت */ $total = (float) $item->get_total(); $unit_price = $quantity > 0 ? $total / $quantity : 0; /* * نوع متغیر * مثال: * تک * کارتن */ $variation_text = self::get_variation_text( $product, $item ); /* * Code همان SKU است. * * نوع متغیر را هم در Description * نگه می‌داریم. */ $article = array( 'Code' => (string) $code, 'Quantity' => $quantity, 'SalePrice' => $unit_price, 'Description' => $variation_text ); $articles[] = $article; } if (empty($articles)) { self::save_response( $order, array( 'success' => false, 'stage' => 'articles', 'message' => 'هیچ کالایی با SKU معتبر در سفارش پیدا نشد.' ) ); wp_safe_redirect( admin_url( 'post.php?post=' . $order_id . '&action=edit' ) ); exit; } /* * ------------------------------------------------- * 3. توضیحات سفارش * ------------------------------------------------- */ $description = $order->get_customer_note(); /* * ------------------------------------------------- * 4. شناسه یکتای سفارش کارا * ------------------------------------------------- */ $kara_order_id = wp_generate_uuid4(); /* * ------------------------------------------------- * 5. پارامترهای SubmitSaleOrderNew * ------------------------------------------------- */ $query = array( 'UserName' => $username, 'Password' => $password, 'CurrentVersionNumber' => $version, 'Id' => $kara_order_id, 'PartnerId' => $partner_id, 'SettlementTypeId' => $settlement_type_id, 'SettlementDay' => $settlement_day, 'Description' => $description, 'VisitTime' => gmdate('Y-m-d\TH:i:s\Z'), 'DiscountPercent' => 0, 'AddedDiscountPercent' => 0, 'CashPrise' => 0, 'GeoLocationAccuracy' => '', 'GeoLocationLat' => '', 'GeoLocationLong' => '', 'WarehouseId' => $warehouse_id, /* * Articles به صورت JSON */ 'Articles' => wp_json_encode( $articles, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ), 'CashSettlementDiscountPercentStepsIndeces' => '' ); /* * ------------------------------------------------- * 6. حالت آزمایشی * ------------------------------------------------- */ $dry_run = !empty($settings['dry_run']); if ($dry_run) { self::save_response( $order, array( 'success' => true, 'dry_run' => true, 'stage' => 'preview', 'message' => 'حالت آزمایشی فعال است؛ هیچ چیزی به کارا ارسال نشد.', 'request' => $query ) ); wp_safe_redirect( admin_url( 'post.php?post=' . $order_id . '&action=edit' ) ); exit; } /* * ------------------------------------------------- * 7. ارسال واقعی به کارا * ------------------------------------------------- */ $url = trailingslashit( $base_url ) . 'MobileApp/General/SubmitSaleOrderNew'; $response = wp_remote_post( $url, array( 'timeout' => 60, 'sslverify' => false, 'headers' => array( 'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8' ), 'body' => $query ) ); if (is_wp_error($response)) { self::save_response( $order, array( 'success' => false, 'stage' => 'http', 'message' => $response->get_error_message(), 'request' => $query ) ); } else { $http_code = wp_remote_retrieve_response_code( $response ); $body = wp_remote_retrieve_body( $response ); self::save_response( $order, array( 'success' => $http_code >= 200 && $http_code < 300, 'stage' => 'submit_sale_order', 'http_code' => $http_code, 'request' => $query, 'response' => json_decode( $body, true ), 'raw' => $body ) ); } /* * نتیجه را در سفارش ووکامرس نشان می‌دهیم. */ wp_safe_redirect( admin_url( 'post.php?post=' . $order_id . '&action=edit' ) ); exit; } /** * پیدا کردن مشتری در کارا بر اساس موبایل */ private static function find_partner( $base_url, $username, $password, $version, $mobile ) { if (!$mobile) { return false; } $url = trailingslashit( $base_url ) . 'MobileApp/General/GetPartners'; $query = array( 'RequestId' => wp_generate_uuid4(), 'UserName' => $username, 'Password' => $password, 'From' => 1, 'Count' => 5000, 'CurrentVersionNumber' => $version ); $response = wp_remote_get( add_query_arg( $query, $url ), array( 'timeout' => 60, 'sslverify' => false ) ); if (is_wp_error($response)) { return false; } $body = wp_remote_retrieve_body( $response ); $json = json_decode( $body, true ); if (!is_array($json)) { return false; } /* * پاسخ کارا ممکن است ساختارهای مختلف داشته باشد. * اینجا چند حالت رایج را بررسی می‌کنیم. */ $partners = array(); if ( isset($json['Data']['Partners']) && is_array( $json['Data']['Partners'] ) ) { $partners = $json['Data']['Partners']; } elseif ( isset($json['Partners']) && is_array( $json['Partners'] ) ) { $partners = $json['Partners']; } foreach ($partners as $item) { $item_mobile = isset($item['Mobile']) ? preg_replace( '/\D+/', '', $item['Mobile'] ) : ''; $wanted_mobile = preg_replace( '/\D+/', '', $mobile ); if ( $item_mobile && $item_mobile === $wanted_mobile ) { return array( 'PartnerId' => $item['Id'] ?? $item['PartnerId'] ?? '', 'raw' => $item ); } } return false; } /** * ساخت مشتری جدید در کارا */ private static function create_partner( $base_url, $username, $password, $version, $first_name, $last_name, $mobile, $phone, $address, $postcode, $national_code, $group_code ) { $url = trailingslashit( $base_url ) . 'MobileApp/General/SubmitPartner'; $partner_id = wp_generate_uuid4(); $body = array( 'UserName' => $username, 'Password' => $password, 'CurrentVersionNumber' => $version, 'FirstName' => $first_name, 'Id' => wp_generate_uuid4(), 'LastName' => $last_name, 'LegalName' => '', 'Phone1' => $phone, 'Phone2' => '', 'Mobile' => $mobile, 'Fax' => '', 'Address' => $address, /* * مشتری حقیقی */ 'IsLegal' => false, 'CalculateVATForThisPerson' => false, 'CreditId' => '', 'GroupCode' => $group_code, 'Changed' => gmdate( 'Y-m-d\TH:i:s\Z' ), 'PartnerFinancialCode' => '', 'PartnerNationalElevenDigitID' => '', 'NationalCode' => $national_code, 'PartnerPostalCode' => $postcode, 'Latitude' => null, 'Longitude' => null ); $response = wp_remote_post( $url, array( 'timeout' => 60, 'sslverify' => false,