ArcWOC/includes/class-hesabix-v2-currency-service.php
morrning 42fbedcf26 Fix 4.9.2: show invoice profit in Hesabix currency (IRR)
Profit amounts are in Hesabix invoice currency; formatting with WC
order currency (IRT/Toman) mislabeled rials as tomans.
2026-08-04 13:16:01 +00:00

340 lines
9.3 KiB
PHP
Executable file

<?php
/**
* ارز فاکتور، فهرست ارزهای کسب‌وکار، تطبیق با ووکامرس، تبدیل تومان→ریال.
*
* @package Hesabix_V2
* @subpackage Hesabix_V2/includes
*/
if (!defined('WPINC')) {
die;
}
class Hesabix_V2_Currency_Service
{
/**
* کش لیست ارزهای کسب‌وکار (ثانیه).
*/
const LIST_CACHE_TTL = 300;
/**
* کلید ترنزینت لیست ارز بر اساس شناسهٔ کسب‌وکار.
*
* @return string
*/
private static function list_transient_key()
{
return 'hesabix_v2_bc_' . (int) get_option('hesabix_v2_business_id');
}
/**
* پاک کردن کش لیست ارزها (پس از ذخیرهٔ تنظیمات یا تغییر اتصال).
*
* @return void
*/
public static function invalidate_list_cache()
{
delete_transient(self::list_transient_key());
}
/**
* استخراج ردیف‌های ارز از پاسخ API.
*
* @param array $res
* @return array<int, array{id:int,code:string,title:string,name:string,is_default:bool}>
*/
public static function normalize_rows_from_api_response($res)
{
if (!is_array($res) || empty($res['success'])) {
return array();
}
$data = isset($res['data']) ? $res['data'] : null;
$items = array();
if (is_array($data)) {
if (isset($data['items']) && is_array($data['items'])) {
$items = $data['items'];
} else {
$keys = array_keys($data);
$numeric_keys = true;
foreach ($keys as $i => $k) {
if ((string) $k !== (string) $i) {
$numeric_keys = false;
break;
}
}
if ($numeric_keys && !empty($keys)) {
$items = $data;
}
}
}
$out = array();
foreach ($items as $row) {
if (!is_array($row) || empty($row['id'])) {
continue;
}
$code = isset($row['code']) ? strtoupper(trim((string) $row['code'])) : '';
$out[] = array(
'id' => (int) $row['id'],
'code' => $code,
'title' => isset($row['title']) ? (string) $row['title'] : '',
'name' => isset($row['name']) ? (string) $row['name'] : '',
'is_default' => !empty($row['is_default']),
);
}
return $out;
}
/**
* دریافت لیست ارزهای کسب‌وکار (با کش).
*
* @param Hesabix_V2_Api|null $api
* @return array<int, array{id:int,code:string,title:string,name:string,is_default:bool}>
*/
public static function get_business_currency_rows(Hesabix_V2_Api $api = null)
{
$key = self::list_transient_key();
$cached = get_transient($key);
if ($cached !== false && is_array($cached)) {
return $cached;
}
$api = $api ?: new Hesabix_V2_Api();
$res = $api->get_business_currencies();
$rows = self::normalize_rows_from_api_response($res);
if (!empty($rows)) {
set_transient($key, $rows, self::LIST_CACHE_TTL);
}
return $rows;
}
/**
* ارز انتخاب‌شده در تنظیمات افزونه یا پیش‌فرض کسب‌وکار.
*
* @param Hesabix_V2_Api|null $api
* @return array{id:int,code:string,title:string,name:string,is_default:bool}|null
*/
public static function resolve_invoice_currency_row(Hesabix_V2_Api $api = null)
{
$rows = self::get_business_currency_rows($api);
if (empty($rows)) {
return null;
}
$opt = (int) get_option('hesabix_v2_currency_id', 0);
if ($opt > 0) {
foreach ($rows as $r) {
if ((int) $r['id'] === $opt) {
return $r;
}
}
return null;
}
foreach ($rows as $r) {
if (!empty($r['is_default'])) {
return $r;
}
}
return $rows[0];
}
/**
* شناسهٔ ارز برای فاکتور.
*
* @param Hesabix_V2_Api|null $api
* @return int
*/
public static function resolve_invoice_currency_id(Hesabix_V2_Api $api = null)
{
$row = self::resolve_invoice_currency_row($api);
if ($row) {
return (int) $row['id'];
}
$fallback = (int) get_option('hesabix_v2_currency_id', 0);
return $fallback > 0 ? $fallback : 1;
}
/**
* کد ارز فروشگاه ووکامرس.
*
* @param string|null $override از سفارش یا همگام‌سازی.
* @return string
*/
public static function get_wc_currency_code($override = null)
{
if ($override !== null && $override !== '') {
return strtoupper(trim((string) $override));
}
if (function_exists('get_woocommerce_currency')) {
return strtoupper(trim((string) get_woocommerce_currency()));
}
return '';
}
/**
* آیا کد ارز ووکامرس به‌منزلهٔ تومان در نظر گرفته شود (IRT، TMN، …).
*
* @param string $code
* @return bool
*/
public static function wc_code_is_toman($code)
{
$c = strtoupper(trim((string) $code));
$tomans = apply_filters('hesabix_v2_wc_toman_currency_codes', array('IRT', 'TMN'));
return in_array($c, array_map('strtoupper', (array) $tomans), true);
}
/**
* قالب‌بندی مبلغ در واحد ارز حسابیکس (نه لزوماً ارز ووکامرس).
*
* سود فاکتور همیشه به ارز سند حسابیکس است؛ اگر با wc_price و ارز فروشگاه
* (مثلاً IRT/تومان) فرمت شود، عدد ریالی با برچسب تومان دیده می‌شود.
*
* @param float $amount
* @param string|null $currency_code مثلاً IRR
* @param string|null $currency_title مثلاً ریال ایران
* @return string
*/
public static function format_hesabix_money($amount, $currency_code = null, $currency_title = null)
{
$amount = (float) $amount;
$code = strtoupper(trim((string) $currency_code));
$title = trim((string) $currency_title);
$formatted = number_format_i18n($amount, 0);
if ($code === 'IRR' || $code === 'RIAL') {
/* translators: %s: amount in Iranian Rial */
return sprintf(__('%s ریال', 'hesabix-v2'), $formatted);
}
if ($title !== '') {
return $formatted . ' ' . $title;
}
if ($code !== '') {
// اگر ارز در ووکامرس تعریف شده باشد از wc_price استفاده کن
if (function_exists('wc_price') && function_exists('get_woocommerce_currencies')) {
$known = get_woocommerce_currencies();
if (is_array($known) && isset($known[ $code ])) {
return wp_strip_all_tags(
wc_price(
$amount,
array(
'currency' => $code,
)
)
);
}
}
return $formatted . ' ' . $code;
}
// fallback: ارز پیش‌فرض فاکتور از تنظیمات افزونه
$row = self::resolve_invoice_currency_row();
if ($row) {
return self::format_hesabix_money(
$amount,
isset($row['code']) ? (string) $row['code'] : '',
isset($row['title']) ? (string) $row['title'] : ''
);
}
return $formatted;
}
/**
* ارزیابی هم‌خوانی ارز ووکامرس با ارز فاکتور حسابیکس و ضریب تبدیل مبلغ.
*
* @param Hesabix_V2_Api|null $api
* @param string|null $wc_currency_override
* @return array{ok:bool,factor:float,currency_id:int,message:string,currency_blocked?:bool}
*/
public static function evaluate_currency_sync(Hesabix_V2_Api $api = null, $wc_currency_override = null)
{
if (!get_option('hesabix_v2_enabled')) {
return array(
'ok' => false,
'factor' => 1.0,
'currency_id' => 0,
'message' => __('همگام‌سازی حسابیکس غیرفعال است.', 'hesabix-v2'),
'currency_blocked' => true,
);
}
$wc = self::get_wc_currency_code($wc_currency_override);
if ($wc === '') {
return array(
'ok' => false,
'factor' => 1.0,
'currency_id' => 0,
'message' => __('ارز فروشگاه ووکامرس مشخص نیست؛ ابتدا واحد پول فروشگاه را تنظیم کنید.', 'hesabix-v2'),
'currency_blocked' => true,
);
}
$api = $api ?: new Hesabix_V2_Api();
$row = self::resolve_invoice_currency_row($api);
if (!$row) {
return array(
'ok' => false,
'factor' => 1.0,
'currency_id' => 0,
'message' => __(
'لیست ارزهای کسب‌وکار از حسابیکس دریافت نشد یا ارز انتخاب‌شده در افزونه دیگر برای این کسب‌وکار فعال نیست. تنظیمات «ارز فاکتور» را بررسی کنید.',
'hesabix-v2'
),
'currency_blocked' => true,
);
}
$hx_code = isset($row['code']) ? strtoupper(trim((string) $row['code'])) : '';
if ($wc === $hx_code) {
return array(
'ok' => true,
'factor' => 1.0,
'currency_id' => (int) $row['id'],
'message' => '',
);
}
if (self::wc_code_is_toman($wc) && $hx_code === 'IRR') {
return array(
'ok' => true,
'factor' => 10.0,
'currency_id' => (int) $row['id'],
'message' => '',
);
}
$label = $row['title'] !== '' ? $row['title'] : ($row['name'] !== '' ? $row['name'] : $hx_code);
return array(
'ok' => false,
'factor' => 1.0,
'currency_id' => (int) $row['id'],
'message' => sprintf(
/* translators: 1: WooCommerce currency code, 2: Hesabix currency code */
__(
'ارز فروشگاه ووکامرس (%1$s) با ارز فاکتور انتخاب‌شده در حسابیکس (%2$s — %3$s) هم‌خوان نیست. تا یکسان کردن ارزها یا استفاده از «تومان» در ووکامرس و «ریال (IRR)» در حسابیکس، همگام‌سازی متوقف می‌ماند.',
'hesabix-v2'
),
$wc,
$hx_code,
$label
),
'currency_blocked' => true,
);
}
}