اگر فروشگاه ووکامرسی شما فقط چند محصول دارد، همان عدد «موجودی انبار» احتمالاً نیازتان را برطرف میکند. اما وقتی تعداد سفارشها بیشتر میشود، محصول متغیر دارید، سفارش پرداختنشده موجودی را موقتاً اشغال میکند، چند نفر موجودی را تغییر میدهند یا باید قبل از تمامشدن کالا برای خرید مجدد تصمیم بگیرید، یک عدد ساده دیگر کافی نیست.
در این آموزش یک لایه مدیریت موجودی پیشرفته روی WooCommerce میسازیم؛ بدون اینکه منطق اصلی انبار ووکامرس را خراب یا دوبارهنویسی کنیم. سیستم نهایی میتواند موجودی فیزیکی، موجودی رزروشده و موجودی قابل فروش را از هم جدا کند، تغییرات انبار را ثبت کند، آستانه سفارش مجدد داشته باشد و بررسیهای دورهای را در پسزمینه انجام دهد.
📌 هدف این مقاله چیست؟ قرار نیست یک ERP کامل را داخل وردپرس بازسازی کنیم. WooCommerce همچنان مرجع فروش و موجودی قابل فروش فروشگاه باقی میماند و ما فقط امکاناتی را اضافه میکنیم که برای کنترل دقیقتر انبار لازماند؛ مثل لاگ تغییرات، موجودی رزروشده، نقطه سفارش مجدد و پردازش دورهای کالاهای کمموجودی.
WooCommerce خودش چه بخشهایی از مدیریت موجودی را انجام میدهد؟
قبل از نوشتن هر افزونهای باید بدانیم چه چیزی از قبل وجود دارد. WooCommerce در تنظیمات اصلی خود میتواند تعداد موجودی را نگه دارد، موجودی را با فروش کاهش دهد، برای کالا آستانه کمبود تعیین کند، Backorder را کنترل کند و برای سفارشهای پرداختنشده موجودی را برای مدت مشخص نگه دارد.
| قابلیت | کار WooCommerce | آیا نیاز به توسعه داریم؟ |
|---|---|---|
| تعداد موجودی | برای محصول یا Variation نگهداری میشود. | خیر؛ از API خود ووکامرس استفاده میکنیم. |
| Hold Stock | موجودی سفارشهای Pending را برای مدت تعیینشده نگه میدارد. | خیر؛ فقط مقدار رزروشده را در گزارش خود میخوانیم. |
| Low Stock | آستانه کمبود و ایمیل هشدار دارد. | برای نقطه سفارش مجدد پیشرفته میتوانیم لایه تکمیلی بسازیم. |
| Backorder | امکان فروش بیشتر از موجودی را طبق سیاست فروشگاه کنترل میکند. | معمولاً خیر. |
| برگرداندن موجودی سفارش | در وضعیتهای مناسب، موجودی کاهشیافته را برمیگرداند. | نباید با کد سفارشی دوباره موجودی را افزایش دهیم. |
در WooCommerce 11.0 یک رفتار مهم نیز اصلاح شد: اگر سفارشی قبلاً باعث کاهش موجودی شده باشد و بعد به وضعیت Failed برود، WooCommerce میتواند همان موجودی کاهشیافته را برگرداند. بنابراین کدی که بدون بررسی دوباره در Failed موجودی را افزایش دهد ممکن است موجودی را دو بار برگرداند.
سه عددی که در سیستم انبار باید از هم جدا باشند
برای مدیریت حرفهای انبار بهتر است فقط به Quantity نگاه نکنیم. سه مقدار مفهوم متفاوتی دارند:
موجودی فیزیکی: مقداری که WooCommerce برای کالا ثبت کرده است.
موجودی رزروشده: مقداری که فعلاً توسط سفارشهای در جریان نگه داشته شده است.
موجودی قابل فروش: موجودی فیزیکی منهای موجودی رزروشده.
مثلاً اگر عدد موجودی محصول ۱۲ باشد اما ۴ عدد در سفارشهای در حال Checkout یا Pending رزرو شده باشند، موجودی آزاد واقعی برای سفارش جدید ۸ عدد است. WooCommerce در کنترلهای Checkout خودش موجودی نگهداشتهشده را در نظر میگیرد؛ ما نیز برای داشبورد مدیریتی از همان منطق رسمی استفاده میکنیم.
مرحله ۱: تنظیمات پایه انبار را درست کنید
از مسیر زیر وارد تنظیمات موجودی شوید:
WooCommerce → Settings → Products → Inventory
گزینه Manage Stock را فعال کنید. سپس Hold Stock را متناسب با زمان واقعی پرداخت فروشگاه تنظیم کنید. اگر درگاه شما ممکن است کاربر را چند دقیقه در مسیر پرداخت نگه دارد، زمان بسیار کوتاه میتواند رزرو کالا را زود آزاد کند؛ زمان بیش از حد طولانی هم ممکن است موجودی را بدون دلیل برای سفارشهای رهاشده قفل نگه دارد.
Low Stock Threshold و Out of Stock Threshold را نیز تنظیم کنید. برای کالاهای مهم میتوانید آستانه کمبود را در سطح خود محصول یا Variation تغییر دهید.
⚠️ نکته: Hold Stock فقط یک عدد تزئینی نیست. WooCommerce از رزرو موجودی برای جلوگیری از Overselling استفاده میکند. ساخت یک سیستم رزرو جداگانه بدون شناخت این مکانیزم میتواند باعث شود موجودی دو بار رزرو شود.
📌 قبل از تغییر کد فروشگاه بکاپ داشته باشید
سیستم انبار مستقیماً روی امکان فروش کالا اثر دارد. قبل از نصب افزونه سفارشی یا تغییر منطق موجودی، راهنمای ساخت بکاپ خودکار وردپرس روی S3 را ببینید تا در صورت خطا، مسیر بازگشت داشته باشید.
مرحله ۲: موجودی قابل فروش را با API رسمی محاسبه کنید
WooCommerce تابع wc_get_held_stock_quantity() را برای خواندن مقداری که در سفارشهای در انتظار رزرو شده است در اختیار توسعهدهنده میگذارد. بنابراین لازم نیست برای پیدا کردن سفارشهای رزروشده مستقیم Query دیتابیس بنویسیم.
کد زیر مقدار فیزیکی، رزروشده و قابل فروش یک محصول را برمیگرداند:
<?php
function iranica_get_inventory_state( int $product_id ): array {
$product = wc_get_product( $product_id );
if ( ! $product instanceof WC_Product ) {
return array(
'error' => 'product_not_found',
);
}
if ( ! $product->managing_stock() ) {
return array(
'error' => 'stock_not_managed',
);
}
$stock_owner_id = $product->get_stock_managed_by_id();
$stock_product = (
$stock_owner_id === $product->get_id()
)
? $product
: wc_get_product( $stock_owner_id );
if ( ! $stock_product instanceof WC_Product ) {
return array(
'error' => 'stock_owner_not_found',
);
}
$physical = (int) $stock_product->get_stock_quantity();
$held = (int) wc_get_held_stock_quantity(
$stock_product,
0
);
return array(
'physical' => $physical,
'held' => $held,
'available' => $physical - $held,
);
}
استفاده از get_stock_managed_by_id() برای محصول متغیر مهم است؛ چون بعضی Variationها موجودی مستقل دارند و بعضی دیگر موجودی والد را به اشتراک میگذارند.
اگر Backorder فعال باشد، ممکن است سیاست فروشگاه اجازه فروش با موجودی صفر یا منفی را بدهد؛ بنابراین عدد Available را بدون توجه به تنظیم Backorder بهعنوان «ممنوعیت فروش» استفاده نکنید.
مرحله ۳: برای تغییر موجودی مستقیم سراغ _stock نروید
برای افزایش یا کاهش موجودی از update_post_meta() روی کلید _stock استفاده نکنید. WooCommerce تابع wc_update_product_stock() را برای همین کار دارد و Data Store آن تغییر موجودی را بهصورت مناسب انجام میدهد.
یک تابع ساده برای ورود کالا، خروج دستی یا اصلاح موجودی میتواند به شکل زیر باشد:
<?php
function iranica_adjust_stock(
int $product_id,
int $quantity,
string $operation = 'set'
) {
$allowed = array(
'set',
'increase',
'decrease',
);
if ( ! in_array( $operation, $allowed, true ) ) {
return new WP_Error(
'invalid_operation',
'Stock operation is invalid.'
);
}
$product = wc_get_product( $product_id );
if ( ! $product instanceof WC_Product ) {
return new WP_Error(
'product_not_found',
'Product was not found.'
);
}
if ( ! $product->managing_stock() ) {
return new WP_Error(
'stock_not_managed',
'Stock management is disabled.'
);
}
return wc_update_product_stock(
$product,
absint( $quantity ),
$operation
);
}
برای ورود ۱۰ عدد کالا:
iranica_adjust_stock(
125,
10,
'increase'
);
برای خروج دستی ۳ عدد:
iranica_adjust_stock(
125,
3,
'decrease'
);
مرحله ۴: لاگ تغییر موجودی بسازید
اگر چند مدیر، API، سیستم حسابداری یا فرایند خودکار موجودی را تغییر دهند، بعد از مدتی سؤال اصلی این میشود: «چه کسی موجودی را از ۲۵ به ۱۴ تغییر داد؟» برای پاسخ به این سؤال باید تاریخچه مستقل داشته باشیم.
برای فروشگاه پرتراکنش، نگهداری لاگ در جدول اختصاصی از ذخیره هزاران رکورد داخل Post Meta تمیزتر است. هنگام فعالسازی افزونه میتوانیم جدول زیر را بسازیم:
<?php
function iranica_inventory_create_log_table() {
global $wpdb;
$table = $wpdb->prefix .
'iranica_inventory_log';
$charset = $wpdb->get_charset_collate();
$sql = "CREATE TABLE {$table} (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
product_id BIGINT UNSIGNED NOT NULL,
sku VARCHAR(100) NULL,
qty_before DECIMAL(20,4) NULL,
qty_after DECIMAL(20,4) NULL,
qty_change DECIMAL(20,4) NULL,
user_id BIGINT UNSIGNED NULL,
source VARCHAR(50) NOT NULL DEFAULT 'woocommerce',
created_at DATETIME NOT NULL,
PRIMARY KEY (id),
KEY product_id (product_id),
KEY created_at (created_at)
) {$charset};";
require_once ABSPATH .
'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
این جدول فقط تاریخچه تغییر را نگه میدارد و مرجع اصلی موجودی نیست. عدد اصلی همچنان باید از WooCommerce خوانده شود؛ در غیر این صورت خیلی زود دو منبع متفاوت برای یک موجودی خواهید داشت.
ثبت مقدار قبل و بعد از تغییر
WooCommerce قبل و بعد از تغییر Stock اکشن اجرا میکند. با نگهداشتن مقدار قبل در حافظه همان درخواست میتوانیم تغییر نهایی را در جدول لاگ ثبت کنیم:
<?php
$GLOBALS['iranica_stock_before'] = array();
function iranica_capture_stock_before(
$product
) {
if ( ! $product instanceof WC_Product ) {
return;
}
$GLOBALS['iranica_stock_before'][
$product->get_id()
] = $product->get_stock_quantity(
'edit'
);
}
add_action(
'woocommerce_product_before_set_stock',
'iranica_capture_stock_before',
10,
1
);
add_action(
'woocommerce_variation_before_set_stock',
'iranica_capture_stock_before',
10,
1
);
function iranica_log_stock_after(
$product
) {
global $wpdb;
if ( ! $product instanceof WC_Product ) {
return;
}
$product_id = $product->get_id();
$before = $GLOBALS[
'iranica_stock_before'
][ $product_id ] ?? null;
$after = $product->get_stock_quantity(
'edit'
);
if (
null === $before ||
(float) $before === (float) $after
) {
return;
}
$wpdb->insert(
$wpdb->prefix .
'iranica_inventory_log',
array(
'product_id' => $product_id,
'sku' => $product->get_sku(),
'qty_before' => $before,
'qty_after' => $after,
'qty_change' => $after - $before,
'user_id' => get_current_user_id()
?: null,
'source' => 'woocommerce',
'created_at' => current_time(
'mysql',
true
),
),
array(
'%d',
'%s',
'%f',
'%f',
'%f',
'%d',
'%s',
'%s',
)
);
unset(
$GLOBALS['iranica_stock_before'][
$product_id
]
);
}
add_action(
'woocommerce_product_set_stock',
'iranica_log_stock_after',
10,
1
);
add_action(
'woocommerce_variation_set_stock',
'iranica_log_stock_after',
10,
1
);
این نسخه پایه تغییر عدد موجودی را ثبت میکند، اما لزوماً علت دقیق تغییر را نمیداند. در نسخه سازمانی میتوانید Context جدا برای «سفارش»، «ورود انبار»، «اصلاح دستی»، «API» و «مرجوعی» نیز به سرویس تغییر موجودی بدهید.
مرحله ۵: نقطه سفارش مجدد را از Low Stock جدا کنید
Low Stock Threshold یعنی «از چه عددی به بعد این کالا کمموجودی محسوب شود». اما نقطه سفارش مجدد میتواند براساس زمان تأمین کالا و سرعت فروش محاسبه شود.
نقطه سفارش مجدد = مصرف متوسط روزانه × زمان تأمین کالا + موجودی اطمینان
مثلاً اگر روزانه بهطور متوسط ۳ عدد کالا میفروشید، تأمینکننده ۷ روز زمان نیاز دارد و میخواهید ۵ عدد موجودی اطمینان داشته باشید:
۳ × ۷ + ۵ = ۲۶
وقتی موجودی قابل فروش به ۲۶ عدد برسد، زمان سفارش مجدد است؛ حتی اگر هنوز کالا تمام نشده باشد.
این فرمول یک مدل مدیریتی است و باید با نوسان فروش، حداقل سفارش تأمینکننده و فصل فروشگاه تطبیق داده شود. بهتر است مقدار Reorder Point را جدا از Low Stock Threshold نگه دارید تا این دو مفهوم با هم قاطی نشوند.
مرحله ۶: بررسی کالاهای کمموجودی را به پسزمینه ببرید
اگر هزاران محصول دارید، نباید هنگام بازشدن داشبورد همه محصولات را اسکن کنید. WooCommerce از Action Scheduler برای اجرای کارهای پسزمینه استفاده میکند و همین ابزار برای اسکن دورهای انبار مناسب است.
نمونه زیر هر ساعت یک Action برای بررسی موجودی برنامهریزی میکند:
<?php
function iranica_schedule_inventory_scan() {
if (
! function_exists(
'as_has_scheduled_action'
) ||
! function_exists(
'as_schedule_recurring_action'
)
) {
return;
}
if (
as_has_scheduled_action(
'iranica_inventory_scan',
array(),
'iranica-inventory'
)
) {
return;
}
as_schedule_recurring_action(
time() + 300,
HOUR_IN_SECONDS,
'iranica_inventory_scan',
array(),
'iranica-inventory',
true
);
}
add_action(
'action_scheduler_init',
'iranica_schedule_inventory_scan'
);
Action Scheduler بعد از اجرا در بخش WooCommerce → Status → Scheduled Actions قابل بررسی است. اگر Job شکست بخورد، لاگ آن را میتوانید از همان بخش ببینید.
اسکن محصولات را صفحهبندی کنید
استفاده از limit = -1 در فروشگاه بزرگ میتواند RAM زیادی مصرف کند. بهتر است محصولات دستهای خوانده شوند:
<?php
add_action(
'iranica_inventory_scan',
function() {
$page = 1;
do {
$result = wc_get_products(
array(
'status' => 'publish',
'limit' => 100,
'page' => $page,
'paginate' => true,
'return' => 'objects',
)
);
foreach (
$result->products as $product
) {
if (
! $product
instanceof WC_Product ||
! $product->managing_stock()
) {
continue;
}
$state =
iranica_get_inventory_state(
$product->get_id()
);
if ( isset( $state['error'] ) ) {
continue;
}
$threshold =
wc_get_low_stock_amount(
$product
);
if (
$state['available']
<= $threshold
) {
// اینجا اعلان مدیریتی،
// ثبت درخواست خرید یا صف
// بررسی تامینکننده را اجرا کنید.
}
}
$page++;
} while (
$page <=
$result->max_num_pages
);
}
);
برای فروشگاه بسیار بزرگ بهتر است حتی همین صفحات نیز به چند Job کوچکتر تقسیم شوند تا یک Action طولانی به Timeout نخورد.
فروشگاه بزرگ روی هاست ضعیف، انبار دقیق هم نخواهد داشت
پردازش سفارش، Action Scheduler، گزارش موجودی، Import/Export و افزونههای فروشگاهی همگی به PHP و دیتابیس وابستهاند. اگر Queueها مرتب عقب میافتند یا مدیریت سفارش کند شده است، فقط کد انبار را مقصر ندانید؛ منابع سرویس، Cron و عملکرد دیتابیس را نیز بررسی کنید.
تماس با پشتیبانی ایرانیکاسرور: 021-91302467
اگر چند انبار دارید چه کنیم؟
هسته WooCommerce معمولاً یک Stock Quantity اصلی برای محصول مدیریت میکند. اگر فروشگاه دو انبار تهران و اصفهان دارد، ذخیرهکردن دو عدد در یک Quantity امکانپذیر نیست.
برای معماری چندانباره بهتر است موجودی هر Location در جدول جدا نگهداری شود و Stock اصلی WooCommerce برابر مجموع «موجودی قابل فروش مکانهای فعال» باشد.
| داده | محل نگهداری | نقش |
|---|---|---|
| موجودی تهران | جدول Location Stock | موجودی همان انبار |
| موجودی اصفهان | جدول Location Stock | موجودی همان انبار |
| موجودی قابل فروش کل | WooCommerce Stock | عددی که Checkout براساس آن فروش را کنترل میکند. |
| تخصیص سفارش | جدول Allocation | مشخص میکند سفارش از کدام انبار ارسال شود. |
در سیستم چندانباره، همگامسازی باید تراکنشی و قابل تکرار باشد. اگر تخصیص سفارش شکست خورد، نباید Stock اصلی کم شود ولی Location Stock دستنخورده بماند. برای فروشگاه کوچک، استفاده از افزونه تخصصی چندانباره میتواند منطقیتر از توسعه اختصاصی باشد.
CSV برای بروزرسانی انبوه هنوز کاربرد دارد
اگر موجودی از فایل تأمینکننده یا نرمافزار دیگری میآید، Import CSV میتواند برای بروزرسانی انبوه مفید باشد. WooCommerce 11.2 در Product CSV Importer بهبودهایی در تطبیق ردیفها داشته است و علاوه بر ID و SKU، در سناریوهای مشخص از شناسههای جهانی محصول هم برای تطبیق استفاده میکند.
بااینحال برای Sync لحظهای، CSV انتخاب مناسبی نیست. در اتصال ERP، حسابداری یا WMS بهتر است API یا Queue داشته باشید تا تغییرات مرحلهبهمرحله ثبت و در صورت خطا Retry شوند.
اشتباههای خطرناک در مدیریت موجودی ووکامرس
کمکردن موجودی دوباره بعد از پرداخت
WooCommerce خودش در وضعیتها و رویدادهای مشخص موجودی سفارش را کاهش میدهد. اگر افزونه شما دوباره همان Quantity سفارش را کم کند، موجودی دو بار کاهش پیدا میکند.
افزایش موجودی دوباره هنگام Cancel یا Failed
برگرداندن موجودی نیز منطق داخلی دارد. قبل از نوشتن Hook سفارشی بررسی کنید آیا سفارش قبلاً موجودی را کاهش داده و آیا WooCommerce خودش آن را Restore کرده است.
آپدیت مستقیم _stock
تغییر مستقیم Meta میتواند Lookup Table، Cache و اکشنهای WooCommerce را دور بزند. از CRUD و توابع Stock رسمی استفاده کنید.
خواندن تمام محصولات در یک درخواست
در فروشگاه بزرگ، بارگذاری همه محصولات برای ساخت گزارش ممکن است RAM و زمان اجرای PHP را مصرف کند. Query را صفحهبندی و پردازشهای سنگین را به Queue منتقل کنید.
نداشتن لاگ تغییرات
اگر Stock اشتباه شود و هیچ تاریخچهای نداشته باشید، تشخیص اینکه خطا از سفارش، Import، کاربر یا API بوده تقریباً غیرممکن میشود.
چکلیست تست قبل از فعالکردن سیستم روی فروشگاه اصلی
| تست | نتیجه مورد انتظار |
|---|---|
| سفارش Pending | موجودی رزروشده در Available Stock دیده شود. |
| پرداخت موفق | موجودی فقط یک بار کاهش پیدا کند. |
| لغو سفارش | در صورت کاهش قبلی، موجودی طبق منطق WooCommerce برگردد. |
| Failed Order | روی WooCommerce 11.x رفتار Restore بهدرستی بررسی شود. |
| Variation مستقل | موجودی همان Variation تغییر کند. |
| Variation با Stock والد | موجودی والد بهعنوان Stock Owner استفاده شود. |
| تغییر دستی انبار | مقدار قبل و بعد در لاگ ثبت شود. |
| Action Scheduler | Job دورهای بدون تکرار ناخواسته و بدون Failed Action اجرا شود. |
پرسشهای متداول
آیا WooCommerce خودش سیستم مدیریت موجودی دارد؟
بله. تعداد موجودی، Backorder، Hold Stock، Low Stock و تغییر موجودی سفارش در هسته وجود دارند. سیستم پیشرفته بهتر است این قابلیتها را تکمیل کند، نه جایگزین آنها شود.
فرق موجودی فیزیکی و موجودی قابل فروش چیست؟
موجودی فیزیکی همان Quantity ثبتشده است؛ موجودی قابل فروش، موجودی فیزیکی منهای مقداری است که فعلاً در سفارشهای در جریان رزرو شده است.
آیا باید برای Pending Order خودمان Stock Reserve بسازیم؟
معمولاً خیر. WooCommerce مکانیزم Hold/Reserve Stock دارد. ساخت سیستم رزرو دوم بدون هماهنگی با منطق هسته میتواند باعث کمبود مصنوعی موجودی شود.
برای تغییر موجودی از update_post_meta استفاده کنیم؟
برای Stock بهتر است از wc_update_product_stock() یا متدهای CRUD محصول استفاده شود تا منطق داخلی WooCommerce دور زده نشود.
آیا این معماری برای محصول متغیر هم مناسب است؟
بله، به شرط اینکه مشخص شود Stock در Variation مدیریت میشود یا والد. متد get_stock_managed_by_id() برای تشخیص همان Stock Owner کاربرد دارد.
برای چند انبار باید Stock اصلی WooCommerce را حذف کنیم؟
خیر. یک معماری معمول این است که موجودی هر Location جدا نگهداری شود و Stock قابل فروش کل با WooCommerce همگام شود. منطق تخصیص سفارش به انبار باید مستقل و قابل Audit باشد.
منابع رسمی این آموزش
🔹 تنظیمات محصولات و Inventory در WooCommerce — مرجع Manage Stock، Hold Stock، هشدار کمبود، Backorder و تنظیمات موجودی.
🔹 WooCommerce Stock Functions — مرجع رسمی کاهش/افزایش موجودی، موجودی رزروشده و توابع Stock.
🔹 تغییر رفتار موجودی Failed Order در WooCommerce 11.0 — توضیح Restore شدن موجودی کاهشیافته برای سفارش Failed.
🔹 Action Scheduler API Reference — مرجع اجرای Jobهای پسزمینه و زمانبندی کارهای دورهای.
🔹 WooCommerce 11.2.1 Release Notes — مرجع نسخه پایدار فعلی در زمان نگارش مقاله.
جمعبندی
مدیریت موجودی پیشرفته در WooCommerce از ساخت یک عدد جدید برای Stock شروع نمیشود. ابتدا باید از مدیریت موجودی، Hold Stock، Backorder و کاهش و بازگشت موجودی خود ووکامرس استفاده کنید. سپس برای نیازهای حرفهای، موجودی قابل فروش را با درنظرگرفتن رزروها محاسبه کنید، تغییرات Stock را در یک لاگ مستقل نگه دارید، Reorder Point داشته باشید و پردازشهای سنگین را با Action Scheduler در پسزمینه اجرا کنید. اگر چند انبار دارید، موجودی Locationها را جدا نگه دارید ولی WooCommerce همچنان باید یک عدد قابل اتکا برای فروش آنلاین دریافت کند.
پردازش موجودی یا سفارشها روی فروشگاه شما کند شده است؟
اگر Scheduled Actionها عقب میافتند، Import موجودی Timeout میشود یا پردازش سفارش فشار زیادی روی PHP و دیتابیس ایجاد میکند، میتوانید قبل از افزایش منابع، کانفیگ سرویس و گلوگاههای وردپرس را بررسی کنید.
تماس با پشتیبانی ایرانیکاسرور: 021-91302467






دیدگاهها (۰)