تقسیم موجودی بین تنوعها
مخاطب: برنامهنویس نرمافزار انبارداری یا داشبورد مدیریتی که میخواهد وضعیت تقسیم موجودی را پایش کند، گروههایی را که بررسی لازم دارند پیدا کند یا یک اجرا را از بیرون شروع کند.
📖 مقدمه
Section titled “📖 مقدمه”اگر یک کالا را در چند رنگ یا با چند گارانتی در دیجیکالا دارید، همهی آنها از یک انبار فروخته میشوند، ولی دیجیکالا برای هر تنوع موجودی جدا میخواهد. تقسیم موجودی موجودی کل هر کد فروشنده را بر اساس نیاز فروش بین تنوعهای آن پخش میکند، تا تنوع پرفروش ناموجود نماند و موجودی روی تنوع کمفروش راکد نشود. این بخش تنها بخش سلر ۳۶۰ است که «موجودی در انبار فروشنده» را خودکار در دیجیکالا مینویسد؛ به همین دلیل قواعد آن سختگیرانه است (بخش هشدارها).
عدد هدف هر تنوع را فقط سلر ۳۶۰ و با همان قواعد پنل تعیین میکند. از طریق API میتوانید گروهها و اجراها را بخوانید، گروهی را کنار بگذارید، تنظیمات را تغییر دهید و یک اجرا را شروع کنید؛ ولی نمیتوانید عدد تنوعی را تعیین کنید.
| کار | مسیر | در دسترس |
|---|---|---|
| فهرست گروهها | GET /v1/stock-split/groups |
فعال |
| یک گروه | GET /v1/stock-split/groups/{group_key} |
فعال |
| کنار گذاشتن گروه از تقسیم یا بازگرداندن آن | PATCH /v1/stock-split/groups/{group_key} |
فاز ۱ |
| فهرست اجراها | GET /v1/stock-split/runs |
فعال |
| شروع یک اجرا | POST /v1/stock-split/runs |
فعال |
| یک اجرا | GET /v1/stock-split/runs/{run_id} |
فعال |
| گزارش هر تنوع در یک اجرا | GET /v1/stock-split/runs/{run_id}/lines |
فعال |
| خواندن تنظیمات | GET /v1/stock-split/settings |
فعال |
| تغییر تنظیمات | PATCH /v1/stock-split/settings |
فاز ۱ |
| روشن یا خاموش کردن تقسیم خودکار | PUT /v1/stock-split/settings/automatic |
فاز ۲ |
و با رویدادهای وبهوک stock_split.run_completed و stock_split.group_needs_attention از پایان هر اجرا و هر گروهی که بررسی شما را لازم دارد خبردار شوید.
⚙️ پیشنیازها
Section titled “⚙️ پیشنیازها”دسترسی (Scope)
Section titled “دسترسی (Scope)”| دسترسی | برچسب در پنل | برای |
|---|---|---|
stock_split:read |
«خواندن تقسیم موجودی» | خواندن گروهها، اجراها، خطوط و تنظیمات |
stock_split:write |
«تنظیم و اجرای تقسیم موجودی» | کنار گذاشتن گروه، تغییر تنظیمات، روشن یا خاموش کردن و شروع اجرا |
stock:read |
«خواندن موجودی و رزرو» | پیشنهاد میشود: برای خواندن موجودی تنوعها پس از اجرا از موجودی |
فعال بودن ماژول و اشتراک
Section titled “فعال بودن ماژول و اشتراک”ماژول «API و وبهوک» باید برای پنل فعال باشد؛ در غیر این صورت پاسخ 403 با خطای module_inactive (ماژول API) یا module_required (ماژول این بخش، با نام آن در detail) برمیگردد. برای پنلی که اشتراک آن به پایان رسیده است، هیچ تقسیم تازهای انجام نمیشود، حتی با درخواست شما: شروع اجرا با خطای subscription_inactive رد میشود و اجراهای خودکار فقط واحدهای برداشتهشدهی اجراهای قبلی را به تنوعها برمیگردانند.
آدرس پایه
Section titled “آدرس پایه”https://api.seller360.ir🧮 مفاهیم
Section titled “🧮 مفاهیم”گروه (StockSplitGroup)
Section titled “گروه (StockSplitGroup)”هر گروه یک کد فروشنده با تنوعهای فعال و تاییدشدهی آن است. موجودی گروه بین تنوعهایش تقسیم میشود و هیچوقت از جمع موجودی فروشندهی آنها بیشتر نمیشود.
| فیلد | برچسب در پنل | معنی |
|---|---|---|
group_key، supplier_code |
«کد فروشنده» | کد کالای گروه. |
excluded |
«کنار گذاشتن از تقسیم موجودی» | کل گروه از تقسیم کنار گذاشته شده است. |
owed_units |
— | واحدهایی که اجرایی از روی بعضی تنوعها برداشته و هنوز روی تنوع دیگری برنگردانده است (واحد فیزیکی). |
owed_since |
— | از کی واحدهای برنگشته وجود دارند. |
needs_attention، attention_reasons |
— | گروه بررسی شما را لازم دارد و چرا (جدول بعد). |
last_run_at |
— | آخرین اجرایی که این گروه را بررسی کرد. |
variants[].excluded |
«کنار گذاشتن از تقسیم موجودی» | این تنوع از تقسیم کنار گذاشته شده است. |
variants[].cap |
«سقف سهم این کد تنوع (عدد)» | بیشترین موجودی که تقسیم به این تنوع میدهد. |
variants[].pack_size |
«تعداد در هر بسته» | تعداد واحد در هر بسته، اگر «بستهی چندتایی» روشن باشد. |
variants[].seller_stock |
«موجودی در انبار فروشنده» | موجودی فروشندهی تنوع. |
دلیلهای نیاز به بررسی
Section titled “دلیلهای نیاز به بررسی”attention_reasons |
معنی |
|---|---|
owed |
واحدهایی از روی تنوعها برداشته و هنوز برگردانده نشده است. |
mismatch |
جمع موجودی گروه پس از تقسیم با پیش از آن برابر نبود. تا وقتی آن را در پنل پاک نکنید باقی میماند. |
inconsistent |
واحدهای محمولهها و رزروها از موجودی ثبتشده بیشتر بود و آخرین اجرا گروه را تغییر نداد. |
اجرا (StockSplitRun)
Section titled “اجرا (StockSplitRun)”| فیلد | برچسب در پنل | معنی |
|---|---|---|
id |
— | شناسهی اجرا. |
trigger |
«نوع اجرا» | scheduled «زمانبندیشده»، urgent «فوری» یا manual «اجرای یکباره». |
urgent_reason |
— | علت اجرای فوری: zero تنوعی ناموجود است که سهم دارد، owed واحدهای برداشتهشدهی قبلی، both هر دو. |
status |
«نتیجه» | وضعیت (جدول بعد). |
stage |
— | مرحلهی فعلی: read، putback، decrease یا increase؛ پیش از شروع و پس از پایان خالی. |
progress |
— | پیشرفت مرحله (step_done از step_total) و بستهها (bundle_done از bundle_total). |
group_keys |
— | گروههای یک اجرای فوری؛ خالی یعنی همه. |
started_at، finished_at |
«زمان» | شروع و پایان اجرا. |
synced_at |
— | پایان همگامسازیای که تقسیم بر دادهی آن انجام شد. |
groups_checked |
«کد کالاهای بررسیشده» | تعداد گروههای بررسیشده. |
groups_written |
— | تعداد گروههایی که تغییر کردند. |
variants_written |
«کد تنوعهای ثبتشده» | تعداد تنوعهایی که عدد تازهشان ثبت شد. |
variants_failed |
«ثبتنشده» | تعداد تنوعهایی که ثبت نشدند. |
units_owed |
— | واحدهای برنگشتهی پنل در پایان اجرا؛ بیشتر از صفر یعنی اجرا هرگز ok نیست. |
mismatched_groups |
— | گروههایی که جمع آنها در بررسی پس از اجرا جور نبود. |
message |
«توضیح» | پیام فارسی نتیجه. |
وضعیتهای اجرا
Section titled “وضعیتهای اجرا”status |
معنی | پایانی؟ |
|---|---|---|
syncing |
در حال همگامسازی پیش از تقسیم. | خیر |
running |
در حال اجرا. | خیر |
ok |
همهی تغییرها ثبت و با شواهد دیجیکالا تایید شد. | بله |
nothing |
تغییری لازم نبود. | بله |
partial |
بخشی ثبت نشد، نتیجهی بخشی هنوز روشن نیست یا به اجرای بعدی موکول شد. | بله |
rate_limited |
به محدودیت دیجیکالا خورد. | بله |
failed |
ناموفق بود. | بله |
skipped |
اجرا نشد؛ مثلا چون همگامسازی پیش از آن کامل نشد. | بله |
خط اجرا (StockSplitLine)
Section titled “خط اجرا (StockSplitLine)”برای هر تنوعی که اجرا عددش را تغییر داد یا میخواست تغییر دهد:
| فیلد | برچسب در پنل | معنی |
|---|---|---|
variant_id، group_key |
«کد تنوع» | تنوع و گروه آن. |
phase |
«نوع» | decrease کاهش یا increase افزایش. |
before |
— | موجودی فروشنده پیش از اجرا. |
target |
— | عددی که تقسیم برای این تنوع تعیین کرد. |
written |
«ثبتشده» | عددی که در دیجیکالا نوشته شد. |
status |
«نتیجه» | written ثبت شد؛ failed ثبت نشد؛ unknown ارسال شد و دیجیکالا نتیجه را بهموقع تایید نکرد؛ skipped به اجرای بعدی موکول شد. |
reason |
«دلیل سهم» | uncovered «بدون پوشش در انبار دیجیکالا»، need «بر اساس نیاز فروش»، covered «پوشش کافی در انبار دیجیکالا»، excluded کنارگذاشته، capped در سقف تعیینشدهی شما، inconsistent اعداد گروه ناسازگار بود. |
error |
— | علت ثبتنشدن یا موکول شدن، به فارسی. |
تنظیمات (StockSplitSettings)
Section titled “تنظیمات (StockSplitSettings)”| فیلد | برچسب در پنل | پیشفرض | معنی |
|---|---|---|---|
enabled |
«تقسیم خودکار» | خاموش | تقسیم خودکار روشن است. |
enabled_at |
— | — | زمان روشن شدن. |
threshold |
«تغییرهای کوچک ثبت نشود» | ۲ | تغییر کمتر از این تعداد نوشته نمیشود؛ تنوع با موجودی صفر که سهم دارد همیشه نوشته میشود. |
min_seller_stock |
«حداقل موجودی در انبار فروشنده برای هر کد تنوع» | ۰ | حداقل موجودی هر تنوع پیش از تقسیم بقیه؛ صفر یعنی خاموش. |
pack_enabled |
«بستهی چندتایی» | خاموش | بعضی تنوعها بستهی چندتایی هستند. |
margin |
— | balanced |
ضریب اطمینان فروش پنل: conservative «محافظهکار» ۰٫۸، balanced «متعادل» ۱، aggressive «تهاجمی» ۱٫۲؛ با پیشنهاد ارسال و پیشنهاد خرید مشترک است و اینجا فقط خواندنی است. |
⏱️ چه وقت اجرا میشود
Section titled “⏱️ چه وقت اجرا میشود”| نوع اجرا | چه وقت |
|---|---|
زمانبندیشده (scheduled) |
هر روز ساعت ۵ صبح به وقت تهران، برای پنلهایی که تقسیم خودکار را روشن کردهاند. |
فوری (urgent) |
هر ۳۰ دقیقه بررسی میشود؛ برای گروهی که واحد برنگشته دارد، یا تنوعی از آن ناموجود است که سهم دارد. هر گروه حداکثر یک بار در ساعت. |
یکباره (manual) |
با «همگامسازی و اجرای یکباره» در پنل، یا POST /v1/stock-split/runs؛ حتی اگر تقسیم خودکار خاموش باشد. |
هر اجرا گروهها را بستهبهبسته (حدود ۵۰ تنوع در هر بسته) میخواند و ثبت میکند، کاهشها را پیش از افزایشها مینویسد و حداکثر حدود ۳۰ دقیقه طول میکشد؛ گروههای باقیمانده در اجرای بعدی تقسیم میشوند.
🔢 تازگی
Section titled “🔢 تازگی”- گروهها و تنظیمات: فوری؛ هر تغییر در همان پاسخ دیده میشود و از اجرای بعدی اثر دارد.
- اجرا:
GET /v1/stock-split/runs/{run_id}در حین اجرا مرحله و پیشرفت فعلی را نشان میدهد. پایان اجرا با رویدادstock_split.run_completedو برای اجرایی که با API شروع شده، با کار ثبتشده و رویدادjob.completedاعلام میشود.
⚠️ هشدارها
Section titled “⚠️ هشدارها”سه قاعدهی اول از قواعد ثابت مالک محصول است و هیچ اجرایی از آنها عبور نمیکند. دو قاعدهی اول جلوی فروش بیش از موجودی را میگیرند و قاعدهی سوم جلوی گم شدن واحدها از فهرست دیجیکالا را.
📡 مسیرها
Section titled “📡 مسیرها”GET /v1/stock-split/groups — گروهها فعال
Section titled “GET /v1/stock-split/groups — گروهها ”GET /v1/stock-split/groups?needs_attention=1 HTTP/1.1Host: api.seller360.irAuthorization: Bearer s360_live_...| پارامتر | نوع | اجباری | توضیح |
|---|---|---|---|
page، size |
عدد | خیر | صفحهبندی؛ پیشفرض ۵۰، بیشینه ۵۰۰. |
needs_attention |
0 یا 1 |
خیر | 1: فقط گروههایی که بررسی شما را لازم دارند. |
excluded |
0 یا 1 |
خیر | فقط گروههای کنارگذاشته (1) یا شرکتکننده (0). |
{ "status": "ok", "data": [ { "group_key": "5144", "supplier_code": "5144", "excluded": false, "owed_units": 6, "owed_since": "2026-11-13T05:12:40+03:30", "needs_attention": true, "attention_reasons": ["owed"], "last_run_at": "2026-11-13T05:12:40+03:30", "variants": [ { "variant_id": 84780448, "title": "سفید", "excluded": false, "cap": null, "pack_size": 1, "seller_stock": 14 }, { "variant_id": 84780452, "title": "مشکی", "excluded": false, "cap": 10, "pack_size": 1, "seller_stock": 0 } ] } ], "pager": { "page": 1, "item_per_page": 50, "total_pages": 1, "total_rows": 1 }}GET /v1/stock-split/groups/{group_key} — یک گروه فعال
Section titled “GET /v1/stock-split/groups/{group_key} — یک گروه ”همان ساختار، برای یک گروه. برای تنوع بدون کد فروشنده، group_key را URL-encode کنید.
PATCH /v1/stock-split/groups/{group_key} — کنار گذاشتن یا بازگرداندن فاز ۱
Section titled “PATCH /v1/stock-split/groups/{group_key} — کنار گذاشتن یا بازگرداندن ”گروه کنارگذاشته در اجراهای بعدی دست نمیخورد و فقط واحدهای برنگشتهاش به آن برگردانده میشوند. فقط در سلر ۳۶۰ ثبت میشود.
{ "excluded": true }| کد HTTP | خطا | معنی | تکرار بیخطر است؟ |
|---|---|---|---|
404 |
not_found |
این گروه در این پنل نیست. | خیر. |
409 |
stock_split_in_progress |
یک اجرا در جریان است. | بله، پس از پایان اجرا. |
409 |
idempotency_mismatch |
این کلید یکتا قبلا با بدنهی دیگری استفاده شده است. | خیر؛ کلید تازه بسازید. |
GET /v1/stock-split/runs — اجراها فعال
Section titled “GET /v1/stock-split/runs — اجراها ”تازهترین اول.
| پارامتر | نوع | اجباری | توضیح |
|---|---|---|---|
page، size |
عدد | خیر | صفحهبندی. |
status |
یکی از وضعیتهای اجرا | خیر | فقط این وضعیت. |
trigger |
scheduled، urgent، manual |
خیر | فقط این نوع اجرا. |
POST /v1/stock-split/runs — شروع یک اجرا فعال
Section titled “POST /v1/stock-split/runs — شروع یک اجرا ”همان «همگامسازی و اجرای یکباره»ی پنل: ابتدا همگامسازی (هشدار ۱)، سپس تقسیم با قواعد پنل. بدنه ندارد. پاسخ فوری 202 فقط یعنی «در صف ثبت شد».
POST /v1/stock-split/runs HTTP/1.1Host: api.seller360.irAuthorization: Bearer s360_live_...Idempotency-Key: split-1405-08-23-1030پاسخ نمونه (کد 202)
{ "status": "ok", "data": { "id": "job_8f2c1e", "kind": "stock_split_run", "status": "queued", "created_at": "2026-11-13T10:30:02+03:30", "finished_at": null, "result": null }}پس از پایان، result.run_id شناسهی اجرا را دارد؛ گزارش آن را با GET /v1/stock-split/runs/{run_id} بخوانید. نحوهی پیگیری کار در کارهای در صف آمده است.
خطاهای این مسیر
| کد HTTP | خطا | معنی | تکرار بیخطر است؟ |
|---|---|---|---|
403 |
subscription_inactive |
اشتراک پنل فعال نیست؛ تقسیم تازه انجام نمیشود. | خیر. |
409 |
stock_split_in_progress |
اجرای دیگری در جریان است. | بله، پس از پایان آن. |
409 |
idempotency_mismatch |
این کلید یکتا قبلا با درخواست دیگری استفاده شده است. | خیر؛ کلید تازه بسازید. |
409 |
idempotency_in_progress |
درخواستی با همین کلید در حال انجام است. | بله، چند ثانیه بعد. |
GET /v1/stock-split/runs/{run_id} — یک اجرا فعال
Section titled “GET /v1/stock-split/runs/{run_id} — یک اجرا ”{ "status": "ok", "data": { "id": 312, "trigger": "manual", "urgent_reason": null, "status": "partial", "stage": null, "progress": { "step_done": 40, "step_total": 40, "bundle_done": 5, "bundle_total": 5 }, "group_keys": null, "started_at": "2026-11-13T10:30:04+03:30", "finished_at": "2026-11-13T10:41:37+03:30", "synced_at": "2026-11-13T10:36:12+03:30", "groups_checked": 64, "groups_written": 9, "variants_written": 23, "variants_failed": 0, "units_owed": 6, "mismatched_groups": [], "message": "۲۳ کد تنوع ثبت شد. ۶ عدد از کد ۵۱۴۴ در اجرای بعدی برگردانده میشود." }}GET /v1/stock-split/runs/{run_id}/lines — گزارش هر تنوع فعال
Section titled “GET /v1/stock-split/runs/{run_id}/lines — گزارش هر تنوع ”به ترتیب گروه. پارامترها: page، size، status (written، failed، unknown، skipped) و group_key.
{ "status": "ok", "data": [ { "variant_id": 84780448, "group_key": "5144", "phase": "decrease", "before": 20, "target": 14, "written": 14, "status": "written", "reason": "need", "error": null }, { "variant_id": 84780452, "group_key": "5144", "phase": "increase", "before": 0, "target": 6, "written": null, "status": "unknown", "reason": "uncovered", "error": "دیجیکالا نتیجه را در مهلت تایید نکرد؛ اجرای بعدی آن را بررسی میکند." } ], "pager": { "page": 1, "item_per_page": 50, "total_pages": 1, "total_rows": 2 }}GET /v1/stock-split/settings — تنظیمات فعال
Section titled “GET /v1/stock-split/settings — تنظیمات ”{ "status": "ok", "data": { "enabled": true, "enabled_at": "2026-10-09T18:20:11+03:30", "threshold": 2, "min_seller_stock": 0, "pack_enabled": false, "margin": "balanced" }}PATCH /v1/stock-split/settings — تغییر تنظیمات فاز ۱
Section titled “PATCH /v1/stock-split/settings — تغییر تنظیمات ”فیلدی که فرستاده نشود تغییر نمیکند. فقط در سلر ۳۶۰ ثبت میشود و از اجرای بعدی اثر دارد.
| فیلد بدنه | نوع | توضیح |
|---|---|---|
threshold |
عدد | ۰ تا ۱۰۰۰. |
min_seller_stock |
عدد | ۰ تا ۱۰۰۰؛ برای تنوع بستهای، به تعداد بسته. |
pack_enabled |
true یا false |
— |
PUT /v1/stock-split/settings/automatic — روشن یا خاموش کردن تقسیم خودکار فاز ۲
Section titled “PUT /v1/stock-split/settings/automatic — روشن یا خاموش کردن تقسیم خودکار ”{ "enabled": true }پاسخ موفق: کد 200 با تنظیمات. پیش از روشن کردن، هشدار ۵ را بخوانید.
🔔 رویدادهای وبهوک
Section titled “🔔 رویدادهای وبهوک”| رویداد | چه وقت |
|---|---|
stock_split.run_completed |
یک اجرا با یکی از وضعیتهای پایانی (ok، nothing، partial، rate_limited، failed، skipped) تمام شد. خطوط را با مسیر گزارش هر تنوع بخوانید. |
stock_split.group_needs_attention |
گروهی برای اولین بار یکی از دلیلهای owed، mismatch یا inconsistent را پیدا کرد. |
job.completed |
کار اجرایی که با POST /v1/stock-split/runs شروع شده بود تمام شد. |
نمونهی پیام stock_split.group_needs_attention
{ "id": "evt_01J0D4WX", "type": "stock_split.group_needs_attention", "created_at": "2026-11-13T10:41:38+03:30", "panel_id": 1, "livemode": true, "data": { "group": { "group_key": "5144", "supplier_code": "5144", "excluded": false, "owed_units": 6, "owed_since": "2026-11-13T10:41:37+03:30", "needs_attention": true, "attention_reasons": ["owed"], "last_run_at": "2026-11-13T10:41:37+03:30", "variants": [ { "variant_id": 84780448, "title": "سفید", "excluded": false, "cap": null, "pack_size": 1, "seller_stock": 14 }, { "variant_id": 84780452, "title": "مشکی", "excluded": false, "cap": 10, "pack_size": 1, "seller_stock": 0 } ] }, "run_id": 312 }}پیام stock_split.run_completed در data.run همان ساختار اجرا را دارد. پیش از استفاده از هر پیام، امضای آن را بررسی کنید.
💻 نمونهکد: شروع یک اجرا
Section titled “💻 نمونهکد: شروع یک اجرا”curl -X POST https://api.seller360.ir/v1/stock-split/runs \ -H "Authorization: Bearer $S360_API_KEY" \ -H "Idempotency-Key: split-1405-08-23-1030"$ch = curl_init("https://api.seller360.ir/v1/stock-split/runs");curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . getenv("S360_API_KEY"), "Idempotency-Key: split-1405-08-23-1030", ], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 20,]);$res = json_decode(curl_exec($ch), true);if (($res["error"]["code"] ?? null) === "stock_split_in_progress") { // اجرای دیگری در جریان است؛ پس از پایان آن دوباره تلاش کنید} else { $jobId = $res["data"]["id"]; // پیگیری با GET /v1/jobs/{job_id}}import os, requests
res = requests.post( "https://api.seller360.ir/v1/stock-split/runs", headers={ "Authorization": f"Bearer {os.environ['S360_API_KEY']}", "Idempotency-Key": "split-1405-08-23-1030", }, timeout=20,).json()if res["status"] == "ok": job_id = res["data"]["id"] # پیگیری با GET /v1/jobs/{job_id}elif res["error"]["code"] == "stock_split_in_progress": ... # اجرای دیگری در جریان استconst res = await fetch('https://api.seller360.ir/v1/stock-split/runs', { method: 'POST', headers: { Authorization: `Bearer ${process.env.S360_API_KEY}`, 'Idempotency-Key': 'split-1405-08-23-1030', },})const body = await res.json()if (body.status === 'ok') { const jobId = body.data.id // پیگیری با GET /v1/jobs/{job_id}} else if (body.error.code === 'stock_split_in_progress') { // اجرای دیگری در جریان است}using var http = new HttpClient();var req = new HttpRequestMessage(HttpMethod.Post, "https://api.seller360.ir/v1/stock-split/runs");req.Headers.Add("Authorization", $"Bearer {Environment.GetEnvironmentVariable("S360_API_KEY")}");req.Headers.Add("Idempotency-Key", "split-1405-08-23-1030");var res = await http.SendAsync(req);var body = await res.Content.ReadFromJsonAsync<JsonElement>();var jobId = body.GetProperty("data").GetProperty("id").GetString();