→ بازگشت به مرکز دانلود

راهنمای جامع یکپارچه‌سازی و پایگاه داده Sadr Scales

مرجع کامل اتصال نرم‌افزارهای POS، ERP و حسابداری؛ ساختار SQL، کالا، ترازو، کلید سریع، فروش و نمونه کد.

نسخه 5.2.1ویرایش 2.1SQL Contract v1SADR-SC-INTEGRATION-5.2.1-01

نقشه سریع پایگاه داده

دسترسی کاربرد حوزه Object
‎Read / Write‎ — قرارداد عمومی ‎v1‎ گروه کالا Master dbo.SADR_ItemClass
‎Read / Write‎ کنترل‌شده — خارج از مسیر پایه ‎v1‎ شعبه Master dbo.SADR_Store
‎Read / Write‎ کنترل‌شده — خارج از مسیر پایه ‎v1‎ تعریف و فعال/غیرفعال‌سازی ترازو Registry dbo.SADR_Scale
‎Replace Transactional‎ — کنترل‌شده گروه‌های هر ترازو Mapping dbo.SADR_ScaleItemClass
‎Read / Write‎ — قرارداد عمومی ‎v1‎ کالا / ‎PLU‎ Master dbo.SADR_Item
‎Read / Write‎ کنترل‌شده کلید سریع گروهی Mapping dbo.SADR_KeyAssignment
‎Replace Transactional‎ — کنترل‌شده کد و کلید اختصاصی هر ترازو Mapping dbo.SADR_ScaleItemMap
‎Read-only‎ — قرارداد عمومی ‎v1‎ ‎Feed‎ تخت فروش Sales dbo.SADR_Logs
‎Read + Ack‎ کنترل‌شده — فروش ساخت‌یافته ‎Header‎ و ریز فاکتور Sales dbo.SADR_Total + SADR_Detail
‎Do not write‎ — داخلی Semantic Sync Internal dbo.SADR_ItemSyncState
حذف ترازو:
برای غیرفعال‌سازی فقط ‎Used=0‎ بگذارید.
DELETE‎ فیزیکی ‎Scale‎ می‌تواند فروش‌ها و ‎Mapping‎های وابسته را نیز حذف
کند‎.‎
فروش: ‎SADR_Logs‎ برای ‎Feed‎ ساده است؛ ‎SADR_Total + SADR_Detail‎ برای ‎Header/Detail‎ و اسکن ‎TotalBarcode‎. در قرارداد، ‎LableStatus‎ پس از ثبت موفق می‌تواند ‎1‎ شود‎.‎

۱. هدف و محدوده سند

این سند مرجع کامل اتصال مستقیم نرم‌افزارهای ثالث به پایگاه داده ‎Sadr Scales 5.2.1‎ است‎.‎ هدف این است که یک نرم‌افزار مجاز بتواند بدون دستکاری منطق پروتکل ترازو، عملیات مدیریتی و تبادل داده را از طریق ‎SQL Server‎ انجام دهد‎.‎

این راهنما دو سطح را پوشش می‌دهد: قرارداد عمومی ‎SQL v1‎ برای یکپارچه‌سازی روزمره، و بخش‌های پیشرفته و کنترل‌شده برای شناخت کامل ‎Schema‎ و عملیات مدیریتی.

• تعریف و ویرایش گروه کالا و شعبه‎.‎

• درج، تنظیم، غیرفعال‌سازی و گروه‌بندی ترازو‎.‎

• درج و ویرایش کالا، کلید سریع و نگاشت اختصاصی کالا به ترازو‎.‎

• خواندن فروش به دو روش تخت (SADR_Logs) و ساخت‌یافته (SADR_Total + SADR_Detail)

• علامت‌گذاری فروش پردازش‌شده، جست‌وجو با بارکد تجمیعی فاکتور و رعایت روابط و محدودیت‌های ‎Schema.‎

در مسیر عمومی ‎v1‎، نرم‌افزار ثالث معمولاً ‎SADR_ItemClass‎ و ‎SADR_Item‎ را می‌نویسد و ‎SADR_Logs‎ را فقط می‌خواند. نوشتن در ‎Registry/Mapping‎ یا جداول فروش ساخت‌یافته فقط در سناریوهای کنترل‌شده این سند انجام شود. سقف مجاز ترازو و قواعد تجاری نصب نیز باید رعایت شوند.

۱.۱ معماری یکپارچه‌سازی

نرم‌افزار ثالث برای عملیات روزمره نباید پروتکل اختصاصی مدل‌های ترازو را دوباره پیاده‌سازی کند‎.‎ رابط عمومی این نسخه، قرارداد ‎SQL Server‎ است و ‎Sadr Scales‎ مسئول ‎Registry‎، ‎Session‎، ‎Retry‎، ارسال/دریافت و تفاوت مدل‌های ترازو باقی می‌ماند‎.‎

POS / ERP / Accounting
↓
Sadr Scales SQL Contract v1
↓
Sadr Scales Runtime
↓
PLUS / LSG / Aclas / مدل‌های پشتیبانی‌شده

در استفاده معمول، نرم‌افزار ثالث یکی یا چند مورد زیر را انجام می‌دهد:

• ثبت یا ویرایش گروه و کالا از طریق ‎Query‎های ‎Parameterized‎.

• مدیریت شعبه و ‎Registry/Mapping‎ فقط در صورت نیاز واقعی و به‌صورت کنترل‌شده.

• خواندن فروش در مسیر پایه از ‎SADR_Logs‎؛ استفاده از ‎SADR_Total + SADR_Detail‎ برای سناریوی ساخت‌یافته و کنترل‌شده.

• نگه‌داری ‎Cursor‎ یا وضعیت مصرف فروش در سیستم مقصد به شکل پایدار و ‎Idempotent.

این سند فقط قابلیت‌های موجود و قابل استفاده در ‎Sadr Scales 5.2.1‎ را مستند می‌کند. در این نسخه رابط عمومی یکپارچه‌سازی ‎SQL Server‎ است و ‎REST API/Webhook‎ عمومی ارائه نشده است.

۲. قواعد پایه قبل از هر اتصال

۱‎.‎ تمام ‎Query‎ها باید ‎Parameterized‎ باشند‎.‎

۲‎.‎ عملیات چندجدولی باید داخل ‎Transaction‎ انجام شوند‎.‎

۳‎.‎ هیچ نرم‌افزار ثالثی نباید ‎rowversion/timestamp‎ را دستی مقداردهی کند‎.‎

۴‎.‎ برای غیرفعال‌سازی ترازو از ‎SADR_Scale.Used = 0‎ استفاده کنید؛ حذف فیزیکی ترازو برای غیرفعال‌سازی ممنوع است‎.‎

۵‎.‎ ستون‌های ‎Runtime‎ مانند ‎Status‎، ‎LastSendItem‎، ‎LastSendKey‎ و ‎LastReceiveFID‎ را بدون دلیل قراردادی تغییر ندهید‎.‎

۶‎.‎ تغییر مستقیم ‎SQL‎، متدهای ‎Runtime‎ برنامه را فراخوانی نمی‌کند؛ بنابراین برای تغییرات ‎Registry/Connection‎ بهتر است ‎Sadr Scales‎ متوقف باشد یا پس از تغییر، ‎Registry/‎اتصال‌ها ‎Reload‎ یا برنامه ‎Restart‎ شود‎.‎

۷. ‎ StoreCode='0'‎ و ‎ItemClassCode='0'‎ رکوردهای پیش‌فرض ‎Schema‎ هستند و نباید بی‌دلیل حذف شوند‎.‎

۸‎.‎ حذف رکورد ‎Master‎ می‌تواند به دلیل ‎Foreign Key‎های ‎ON DELETE CASCADE‎ داده وابسته را حذف کند؛ قبل از هر ‎DELETE‎ روابط این سند را بررسی کنید‎.‎

۹‎. Batch‎های بزرگ را به اندازه‌های قابل کنترل تقسیم کنید و ‎Transaction‎ طولانی در زمان اوج فروش نگه ندارید‎.‎

۱۰‎.‎ در ‎Deadlock‎ یا خطاهای موقت ‎SQL‎، ‎Retry‎ محدود با فاصله افزایشی انجام دهید؛ ‎Retry‎ نامحدود مجاز نیست‎.‎

۱۱‎. Connection String‎، نام کاربری و رمز عبور مشتری نباید داخل ‎Source‎ عمومی، ‎Log‎ یا ‎Repository‎ ثبت شود‎.‎

۱۲‎.‎ عملیات ‎Import‎ و مصرف فروش باید ‎Idempotent‎ طراحی شوند تا اجرای دوباره باعث ثبت مالی تکراری نشود‎.‎

نکته:
قرارداد عمومی ‎SQL v1‎ برای کار روزمره بر
‎SADR_ItemClass‎، ‎SADR_Item‎ و خواندن ‎SADR_Logs‎ تکیه دارد. بخش‌های
‎Registry/Mapping‎ و وضعیت‌های فروش ساخت‌یافته در این راهنما برای سناریوهای
کنترل‌شده و شناخت کامل ‎Schema‎ آمده‌اند. فیلدهای ‎Runtime‎ و جدول ‎Sync‎ داخلی
همچنان در مالکیت خود ‎Sadr Scales‎ هستند.

۳. فهرست کامل Objectهای اصلی پایگاه داده

دسترسی پیشنهادی نرم‌افزار ثالث نقش نوع Object
‎Read / Insert / Update‎ — قرارداد عمومی ‎v1‎ گروه کالا Table dbo.SADR_ItemClass
‎Read / Insert / Update‎ کنترل‌شده؛ خارج از مسیر پایه ‎v1‎ شعبه/فروشگاه Table dbo.SADR_Store
‎Read / Insert / Update‎ کنترل‌شده؛ ‎Delete‎ فقط با آگاهی از پاک‌شدن فروش ‎Registry‎ و تنظیمات ترازو Table dbo.SADR_Scale
‎Read / Replace‎ داخل ‎Transaction‎؛ کنترل‌شده رابطه چندبه‌چند ترازو و گروه کالا Table dbo.SADR_ScaleItemClass
‎Read / Insert / Update‎ — قرارداد عمومی ‎v1‎؛ ‎DeleteFlag‎ ترجیح دارد ‎Master‎ کالا/‎PLU‎ Table dbo.SADR_Item
‎Read / Insert / Update / Delete‎ کنترل‌شده کلید سریع گروهی Table dbo.SADR_KeyAssignment
‎Read / Replace‎ داخل ‎Transaction‎؛ کنترل‌شده کد کالا و کلید سریع اختصاصی هر ترازو Table dbo.SADR_ScaleItemMap
‎Read‎؛ ‎LableStatus‎ فقط برای وضعیت مصرف همان نرم‌افزار مقصد ‎Header‎ فاکتور Table dbo.SADR_Total
‎Read‎؛ ‎ItemStatus‎ در صورت نیاز همان مصرف‌کننده ریز اقلام فاکتور Table dbo.SADR_Detail
‎Read-only‎ — قرارداد عمومی ‎v1‎ ‎Feed‎ تخت فروش Table dbo.SADR_Logs
عمدتاً ‎Read-only‎ تاریخچه تغییر قیمت در ‎UI‎ Table dbo.SADR_PriceLog
‎Internal‎؛ دستکاری ممنوع وضعیت داخلی ‎Semantic Sync‎ Table dbo.SADR_ItemSyncState
‎Read‎؛ برای سازگاری و تشخیص نسخه تغییر نمای کالا + نسخه ‎Semantic/Raw‎ View dbo.SADR_ViewPlu
‎Read‎؛ خود برنامه از آن برای ‎CRUD‎ نیز استفاده می‌کند نمای کلید سریع + ‎LastUpdate‎ View dbo.SADR_ViewKey
‎Read-only‎؛ ‎Legacy‎ نام سازگار قدیمی برای ‎SADR_Logs‎ View dbo.JHMA_Logs

۴. نقشه روابط جداول

نقشه روابط جداول پایگاه داده Sadr Scales
خط پیوسته: رابطه Foreign Key — خط‌چین: رابطه منطقی یا داخلی بدون Foreign Key مستقیم. برای مشاهده در اندازه کامل روی نقشه کلیک کنید.

روابط مهم ‎Schema:

• SADR_Item.ItemClassCode → SADR_ItemClass.ItemClassCode

• SADR_Scale.ItemClassCode → SADR_ItemClass.ItemClassCode

• SADR_Scale.StoreCode → SADR_Store.StoreCode

• SADR_ScaleItemClass.ScaleID → SADR_Scale.ScaleID با ON DELETE CASCADE

• SADR_ScaleItemClass.ItemClassCode → SADR_ItemClass.ItemClassCode

• SADR_ScaleItemMap.ScaleID → SADR_Scale.ScaleID با ON DELETE CASCADE

• SADR_ScaleItemMap.PluNo → SADR_Item.PluNo با ON DELETE CASCADE

• SADR_Total.ScaleID → SADR_Scale.ScaleID با ON DELETE CASCADE

• SADR_Detail.TotalID → SADR_Total.TotalID با ON DELETE CASCADE

• SADR_Logs.DeviceNo → SADR_Scale.ScaleID با ON DELETE CASCADE

• SADR_KeyAssignment.ItemClassCode → SADR_ItemClass.ItemClassCode

نکته: `‎SADR_KeyAssignment.PluNo`‎ در ‎Schema‎ فعلی ‎Foreign Key‎ مستقیم به `‎SADR_Item`‎ ندارد، اما از نظر قرارداد باید به یک ‎PLU‎ معتبر اشاره کند‎.‎ قبل از تعریف کلید سریع وجود کالا را بررسی کنید‎.‎

۵. ترتیب امن ساخت داده‌های Master

برای ایجاد یک محیط کامل، ترتیب پیشنهادی این است:

۱‎.‎ ایجاد یا اطمینان از وجود ‎SADR_Store.‎

۲‎.‎ ایجاد یا اطمینان از وجود ‎SADR_ItemClass.‎

۳‎.‎ ایجاد ‎SADR_Scale‎ با گروه پیش‌فرض معتبر‎.‎

۴‎.‎ ثبت گروه‌های اضافی ترازو در ‎SADR_ScaleItemClass.‎

۵‎.‎ درج کالاها در ‎SADR_Item‎ با ‎ItemClassCode‎ معتبر‎.‎

۶‎.‎ تعریف ‎SADR_KeyAssignment‎ برای کلیدهای گروهی در صورت نیاز‎.‎

۷‎.‎ تعریف ‎SADR_ScaleItemMap‎ برای مدل‌هایی که نگاشت اختصاصی هر ترازو دارند‎.‎

۸‎.‎ در تغییر گروه/‎Map‎، ‎Cursor‎های ارسال مرتبط را طبق الگوی برنامه ‎Reset‎ کنید‎.‎

۶. جدول گروه کالا — SADR_ItemClass

ساختار:

توضیح الزام نوع ستون
کد یکتای گروه PK / NOT NULL varchar(50) ItemClassCode
نام گروه Nullable nvarchar(100) ItemClassName
توضیح Nullable nvarchar(150) Descriptions

‎Schema‎ به‌صورت پیش‌فرض گروه 0 با نام «پیش‌فرض» می‌سازد‎.‎

الگوی ‎Upsert‎ مطابق رفتار ‎Sadr Scales:‎

SQL
IF NOT EXISTS
(
    SELECT 1
    FROM dbo.SADR_ItemClass
    WHERE ItemClassCode = @ItemClassCode
)
BEGIN
    INSERT INTO dbo.SADR_ItemClass
        (ItemClassCode, ItemClassName, Descriptions)
    VALUES
        (@ItemClassCode, @ItemClassName, @Descriptions);
END
ELSE
BEGIN
    UPDATE dbo.SADR_ItemClass
    SET ItemClassName = @ItemClassName,
        Descriptions = @Descriptions
    WHERE ItemClassCode = @ItemClassCode;
END;

قبل از حذف گروه بررسی کنید که در SADR_Item، SADR_Scale، SADR_ScaleItemClass یا SADR_KeyAssignment استفاده نشده باشد‎.‎ برای جابه‌جایی گروه، ابتدا وابستگی‌ها را به گروه دیگری منتقل کنید‎.‎

۷. جدول شعبه — SADR_Store

ساختار:

توضیح الزام نوع ستون
کد یکتای شعبه PK / NOT NULL varchar(50) StoreCode
نام شعبه Nullable nvarchar(100) StoreName
توضیح Nullable nvarchar(150) Descriptions

‎Schema‎ رکورد پیش‌فرض StoreCode='0' را ایجاد می‌کند‎.‎

SQL
IF NOT EXISTS
(
    SELECT 1 FROM dbo.SADR_Store WHERE StoreCode = @StoreCode
)
    INSERT INTO dbo.SADR_Store(StoreCode, StoreName, Descriptions)
    VALUES(@StoreCode, @StoreName, @Descriptions);
ELSE
    UPDATE dbo.SADR_Store
    SET StoreName=@StoreName, Descriptions=@Descriptions
    WHERE StoreCode=@StoreCode;

SADR_Scale.StoreCode به این جدول ‎Foreign Key‎ دارد‎.‎ SADR_Scale.StoreName نیز یک متن نمایشی مستقل است؛ در درج معمول فعلی ‎Sadr Scales‎، StoreName ثبت می‌شود و StoreCode می‌تواند روی مقدار پیش‌فرض 0 باقی بماند‎.‎ اگر ‎Integration‎ شما ‎Master‎ شعبه را مدیریت می‌کند، هر دو را سازگار نگه‌دارید‎.‎

۸. Registry ترازو — SADR_Scale

۸.۱ ستون‌ها

توضیح مالکیت نوع ستون
شماره یکتای ترازو؛ صفر ممنوع Config int ScaleID
پورت ارتباط Config int Port
‎MAC/Serial‎ در مدل‌های مربوط Runtime/Hardware varchar(50) Mac
‎FK‎ به شعبه؛ پیش‌فرض ‎0‎ Config varchar(50) StoreCode
گروه اصلی/پیش‌فرض؛ ‎FK‎ Config varchar(50) ItemClassCode
مدل: ‎LSG, LSG_24D, TSG, PLUS, LS6‎ Config nvarchar(50) Category
نسخه دستگاه Runtime/Hardware varchar(50) Version
نام نمایشی ترازو Config nvarchar(50) DeviceName
نام نمایشی شعبه/محل Config nvarchar(50) StoreName
‎IP‎ ترازو Config varchar(20) ScaleIP
‎Online/Offline‎؛ برای فعال/غیرفعال‌کردن استفاده نشود Runtime varchar(50) Status
‎Cursor/‎نسخه آخرین ارسال کالا Runtime bigint LastSendItem
‎Cursor/‎نسخه آخرین ارسال کلید Runtime bigint LastSendKey
‎Cursor‎ دریافت فروش در مدل مربوط Runtime int LastReceiveFID
‎0‎، ‎40‎ یا ‎63‎ Config smallint HotKeyCountPerPage
‎0‎ یا ‎1‎ تا ‎3‎ Config tinyint HotKeyPageCount
ارسال خودکار تغییر کالا Config bit AutoSendItems
دریافت خودکار فروش Config bit AutoGetInvoice
درخواست/وضعیت ارسال تنظیمات به دستگاه Runtime/Handshake bit SendScaleDetail
درخواست/وضعیت دریافت تنظیمات Runtime/Handshake bit GetScaleDetail
‎1‎ فعال، ‎0‎ غیرفعال Config int Used

قیدهای مهم:

  • ScaleID <> 0

  • (ScaleIP, Port) در ‎DB‎ یکتا است‎.‎

  • خود ‎Sadr Scales‎ هنگام درج، تکراری بودن کل ‎ScaleIP‎ یا ‎ScaleID‎ را رد می‌کند؛ ‎Integration‎ نیز همین قانون سخت‌گیرانه‌تر را رعایت کند‎.‎

  • ‎HotKey layout‎ فقط 0/0 یا 40 یا 63 کلید در صفحه و ‎1‎ تا ‎3‎ صفحه است‎.‎

۸.۲ پیش‌فرض مدل‌ها

چیدمان کلید سریع پیش‌فرض ‎AutoGetInvoice‎ در ‎UI‎ پورت پیش‌فرض مدل
63 × 3 قابل انتخاب؛ پیش‌فرض خاموش 33581 LSG
63 × 3 قابل انتخاب؛ پیش‌فرض خاموش 33581 LSG_24D
40 × 3 قابل انتخاب؛ پیش‌فرض خاموش 33581 TSG
0 × 0 روشن و در ‎UI‎ اجباری 5000 PLUS
‎0‎ × ‎0‎ در ‎Registry‎ قابل استفاده 5002 LS6

۸.۳ درج ترازو

درج باید ‎Transactional‎ باشد و همزمان رکورد گروه اولیه را در SADR_ScaleItemClass بسازد‎.‎

SQL
SET XACT_ABORT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;

IF EXISTS
(
    SELECT 1
    FROM dbo.SADR_Scale WITH (UPDLOCK, HOLDLOCK)
    WHERE ScaleIP = @ScaleIP OR ScaleID = @ScaleID
)
    THROW 50001, 'Duplicate ScaleIP or ScaleID', 1;

INSERT INTO dbo.SADR_Scale
(
    ScaleID, ScaleIP, Port, Category,
    DeviceName, StoreName, StoreCode, ItemClassCode,
    AutoSendItems, AutoGetInvoice,
    GetScaleDetail, SendScaleDetail, Used,
    HotKeyCountPerPage, HotKeyPageCount
)
VALUES
(
    @ScaleID, @ScaleIP, @Port, @Category,
    @DeviceName, @StoreName, @StoreCode, @ItemClassCode,
    @AutoSendItems, @AutoGetInvoice,
    1, 0, @Used,
    @HotKeyCountPerPage, @HotKeyPageCount
);

INSERT INTO dbo.SADR_ScaleItemClass(ScaleID, ItemClassCode)
VALUES(@ScaleID, @ItemClassCode);

UPDATE dbo.SADR_Scale
SET LastSendItem = 0, LastSendKey = 0
WHERE ScaleID = @ScaleID;

COMMIT;

قبل از درج مطمئن شوید StoreCode و ItemClassCode موجودند‎.‎ همچنین فعال‌سازی یا افزودن ترازو نباید سقف لایسنس نصب را دور بزند‎.‎

۸.۴ ویرایش ترازو

در ‎UI‎ فعلی ‎5.2.1‎ عملیات ویرایش روزمره روی نام، نام شعبه، گروه اصلی، ‎AutoSend‎، ‎AutoGet‎ و ‎Used‎ انجام می‌شود‎.‎ تغییر مستقیم ‎IP/Port/Model‎ از طریق ‎SQL‎ ممکن است، اما چون ‎Runtime Session‎ بر پایه این فیلدهاست باید فقط در حالت کنترل‌شده انجام شود و پس از آن ‎Registry/Connection Reload‎ یا ‎Restart‎ گردد‎.‎

نمونه ویرایش تنظیمات اصلی:

SQL
SET XACT_ABORT ON;
BEGIN TRANSACTION;

UPDATE dbo.SADR_Scale
SET DeviceName = @DeviceName,
    StoreName = @StoreName,
    StoreCode = @StoreCode,
    ItemClassCode = @ItemClassCode,
    AutoSendItems = @AutoSendItems,
    AutoGetInvoice = @AutoGetInvoice,
    Used = @Used,
    GetScaleDetail = 0,
    SendScaleDetail = 1,
    LastSendItem = 0,
    LastSendKey = 0
WHERE ScaleID = @ScaleID;

DELETE FROM dbo.SADR_ScaleItemClass
WHERE ScaleID = @ScaleID;

INSERT INTO dbo.SADR_ScaleItemClass(ScaleID, ItemClassCode)
VALUES(@ScaleID, @ItemClassCode);

COMMIT;

اگر ترازو چند گروه دارد، بعد از ‎Update‎ گروه اصلی، همه گروه‌های موردنظر را طبق بخش SADR_ScaleItemClass دوباره درج کنید‎.‎

۸.۵ غیرفعال‌کردن ترازو

روش درست:

SQL
UPDATE dbo.SADR_Scale
SET Used = 0
WHERE ScaleID = @ScaleID;

فعال‌سازی مجدد:

SQL
UPDATE dbo.SADR_Scale
SET Used = 1
WHERE ScaleID = @ScaleID;
نکته بسیار مهم: برای غیرفعال‌سازی ترازو، هرگز رکورد آن را با دستور
DELETE FROM SADR_Scale حذف نکنید. حذف فیزیکی ترازو می‌تواند اطلاعات فروش
ثبت‌شده در SADR_Logs، اطلاعات فاکتور در جداول Header/Detail و همچنین
Mappingهای وابسته را حذف کند. دلیل این رفتار، وجود روابط Foreign Key با
Cascade Delete در ساختار فعلی پایگاه داده است.

قرار دادن ستون Status روی مقدار Offline معادل غیرفعال‌کردن ترازو نیست؛ این ستون توسط ‎Runtime‎ برای وضعیت اتصال استفاده می‌شود‎.‎

۹. گروه‌های اختصاص‌یافته به ترازو — SADR_ScaleItemClass

این جدول رابطه چندبه‌چند ترازو و گروه کالا را نگه می‌دارد‎.‎

نقش ستون
‎FK‎ به ترازو ScaleID
‎FK‎ به گروه کالا ItemClassCode

Primary Key: (ScaleID, ItemClassCode).

برای جایگزینی گروه‌های یک ترازو، همان الگوی خود برنامه را استفاده کنید:

SQL
SET XACT_ABORT ON;
BEGIN TRANSACTION;

DELETE FROM dbo.SADR_ScaleItemClass
WHERE ScaleID = @ScaleID;

INSERT INTO dbo.SADR_ScaleItemClass(ScaleID, ItemClassCode)
VALUES(@ScaleID, @Group1),
      (@ScaleID, @Group2);

UPDATE dbo.SADR_Scale
SET LastSendItem = 0
WHERE ScaleID = @ScaleID;

COMMIT;

حداقل یک گروه معتبر داشته باشید و بهتر است SADR_Scale.ItemClassCode نیز در این مجموعه وجود داشته باشد‎.‎

۱۰. Master کالا — SADR_Item

۱۰.۱ ستون‌ها

توضیح نوع عملی ستون #
‎Legacy/‎کمکی int ID 1
‎Legacy/‎کمکی int IDitem 2
گروه کالا؛ ‎FK‎ varchar(50) ItemClassCode 3
شناسه یکتا و غیرصفر int PluNo 4
واحد کالا؛ پیش‌فرض ‎3‎ int PluUnit 5
قیمت واحد int UnitPrice 6
فرمت چاپ int PrintFormat 7
قیمت/هزینه کمکی int PluCost 8
فرمت بارکد int BarFormat 9
پرچم‌های بارکد int BarFlags 10
کد کالا varchar(10) ItemCode 11
بارکد/ایندکس varchar(50) IndexBarcode 12
وزن ظرف float Tare 13
تاریخ/عمر مصرف قراردادی int ShelfDate 14
چاپ ‎Shelf Date‎ int ShelfDatePrint 15
چاپ تاریخ فروش int SaleDatePrint 16
چاپ ساعت فروش int SaleTimePrint 17
‎Mode/Tare‎ در ‎SQL‎ int OnlyTare 18
شماره/کد مالیات int TaxNo 19
نرخ مالیات float TaxRate 20
نام کالا nvarchar(100) PluName 21
متن‌های تکمیلی nvarchar(100) Text1..Text7 22-28
حذف منطقی/غیرفعال‌سازی کالا int DeleteFlag 29
فیلد سازگار قدیمی/ارسال int SendFlag 30
داخلی ‎SQL‎؛ هرگز دستی ننویسید rowversion TimeStamp 31

‎PluNo‎ یکتا است و مقدار صفر ممنوع است. ستون‌های ‎TaxNo‎ و ‎SendFlag‎ در ‎Schema‎ وجود دارند، اما نمونه‌های قرارداد عمومی ‎v1‎ آن‌ها را نمی‌نویسند و مقدار پیش‌فرض پایگاه داده حفظ می‌شود.

نکته: `‎OnlyTare`‎ نام فیلد ‎SQL‎ است‎.‎ در ‎Excel Import‎ خود ‎Sadr Scales‎، ستون متناظر با مفهوم `‎PluMode`‎ خوانده می‌شود؛ این دو نام را در ‎Integration‎ با هم اشتباه نکنید‎.‎

۱۰.۲ Upsert کالا

SQL
SET XACT_ABORT ON;
BEGIN TRANSACTION;

IF NOT EXISTS (SELECT 1 FROM dbo.SADR_Item WHERE PluNo=@PluNo)
BEGIN
    INSERT INTO dbo.SADR_Item
    (
        ItemClassCode, PluNo, PluUnit, UnitPrice,
        PrintFormat, PluCost, BarFormat, BarFlags,
        ItemCode, IndexBarcode, Tare,
        ShelfDate, ShelfDatePrint, SaleDatePrint, SaleTimePrint,
        OnlyTare, TaxRate, PluName,
        Text1, Text2, Text3, Text4, Text5, Text6, Text7,
        DeleteFlag
    )
    VALUES
    (
        @ItemClassCode, @PluNo, @PluUnit, @UnitPrice,
        @PrintFormat, @PluCost, @BarFormat, @BarFlags,
        @ItemCode, @IndexBarcode, @Tare,
        @ShelfDate, @ShelfDatePrint, @SaleDatePrint, @SaleTimePrint,
        @OnlyTare, @TaxRate, @PluName,
        @Text1, @Text2, @Text3, @Text4, @Text5, @Text6, @Text7,
        @DeleteFlag
    );
END
ELSE
BEGIN
    UPDATE dbo.SADR_Item
    SET ItemClassCode=@ItemClassCode,
        PluUnit=@PluUnit,
        UnitPrice=@UnitPrice,
        PrintFormat=@PrintFormat,
        PluCost=@PluCost,
        BarFormat=@BarFormat,
        BarFlags=@BarFlags,
        ItemCode=@ItemCode,
        IndexBarcode=@IndexBarcode,
        Tare=@Tare,
        ShelfDate=@ShelfDate,
        ShelfDatePrint=@ShelfDatePrint,
        SaleDatePrint=@SaleDatePrint,
        SaleTimePrint=@SaleTimePrint,
        OnlyTare=@OnlyTare,
        TaxRate=@TaxRate,
        PluName=@PluName,
        Text1=@Text1, Text2=@Text2, Text3=@Text3, Text4=@Text4,
        Text5=@Text5, Text6=@Text6, Text7=@Text7,
        DeleteFlag=@DeleteFlag
    WHERE PluNo=@PluNo;
END;

COMMIT;

بهترین عملکرد این است که فقط در صورت تغییر واقعی محتوا ‎UPDATE‎ کنید‎. Sadr Scales 5.2.1 Semantic Fingerprint‎ دارد و ‎UPDATE‎ بی‌اثر را از تغییر واقعی جدا می‌کند، اما نوشتن بی‌دلیل همه رکوردها در هر ‎Cycle‎ توصیه نمی‌شود‎.‎

۱۰.۳ حذف کالا

برای ‎Integration‎ عمومی، DeleteFlag را به حذف فیزیکی ترجیح دهید تا چرخه همگام‌سازی بتواند حذف/غیرفعال‌شدن کالا را مشاهده کند‎.‎

حذف فیزیکی SADR_Item می‌تواند رکوردهای SADR_ScaleItemMap همان ‎PLU‎ را به دلیل ‎Cascade Delete‎ حذف کند‎.‎ جدول ‎Sync‎ داخلی نیز باید توسط خود ‎Sadr Scales‎ مدیریت شود‎.‎

۱۱. کلید سریع گروهی — SADR_KeyAssignment

ساختار:

توضیح ستون
گروه کالا ItemClassCode
شماره صفحه؛ در قرارداد معمول صفرمبنا PageNo
شماره کلید داخل صفحه KeyNo
‎PLU‎ اختصاص‌یافته PluNo
‎rowversion‎ داخلی TimeStamp

Primary Key: (ItemClassCode, PageNo, KeyNo).

Upsert:

SQL
IF EXISTS
(
    SELECT 1
    FROM dbo.SADR_KeyAssignment
    WHERE ItemClassCode=@Group
      AND PageNo=@PageNo
      AND KeyNo=@KeyNo
)
    UPDATE dbo.SADR_KeyAssignment
    SET PluNo=@PluNo
    WHERE ItemClassCode=@Group
      AND PageNo=@PageNo
      AND KeyNo=@KeyNo;
ELSE
    INSERT INTO dbo.SADR_KeyAssignment
        (ItemClassCode, PageNo, KeyNo, PluNo)
    VALUES
        (@Group, @PageNo, @KeyNo, @PluNo);

برای آزادکردن یک کلید می‌توانید رکورد را حذف کنید‎.‎ پس از تغییر کلید سریع گروهی، برای ترازوهای مربوط LastSendKey=0 قرار دهید تا ارسال بعدی از ابتدا ارزیابی شود‎.‎

برای ‎LSG/TSG‎ چیدمان ‎UI‎ به این شکل است:

  • ‎LSG/LSG_24D: 63‎کلید در هر صفحه، ‎3‎ صفحه پیش‌فرض‎.‎

  • ‎TSG: 40‎کلید در هر صفحه، ‎3‎ صفحه پیش‌فرض‎.‎

  • PageNoصفرمبنا است؛ مثلاً در چیدمان ‎63‎تایی، کلید نمایشی ‎64‎ برابر PageNo=1, KeyNo=1 است‎.‎

در ‎LS6/Aclas‎ قرارداد کلیدهای خاص و رزروشده وجود دارد؛ نرم‌افزار ثالث نباید بدون تطبیق با منطق مدل، کلیدهای ویژه را بازنویسی کند‎.‎

۱۲. نگاشت اختصاصی کالا به هر ترازو — SADR_ScaleItemMap

این جدول با SADR_KeyAssignment فرق دارد‎.‎ KeyAssignment گروه‌محور است؛ ScaleItemMap برای یک ترازوی مشخص کد محلی کالا و در صورت نیاز جای کلید سریع را نگه می‌دارد‎.‎

در ‎UI 5.2.1‎ این قابلیت برای مدل‌های LSG, LSG_24D, TSG ارائه می‌شود‎.‎

محدودیت ستون
ترازو؛ بخشی از ‎PK‎ ScaleID
‎PLU‎؛ بخشی از ‎PK‎ و ‎FK‎ به کالا PluNo
کد محلی روی ترازو؛ > ‎0‎ و در هر ‎Scale‎ یکتا ItemCode
‎Null‎ یا ‎0..2‎ PageNo
‎Null‎ یا > ‎0‎ KeyNo

قواعد:

  • PK = (ScaleID, PluNo)

  • (ScaleID, ItemCode) یکتا است‎.‎

  • (ScaleID, PageNo, KeyNo) در صورت داشتن ‎HotKey‎ یکتا است‎.‎

  • PageNoو KeyNo باید یا هر دو ‎Null‎ باشند یا هر دو مقدار داشته باشند‎.‎

  • جای کلید باید داخل HotKeyCountPerPage و HotKeyPageCount همان ترازو باشد‎.‎

روش امن جایگزینی ‎Map:

SQL
SET XACT_ABORT ON;
BEGIN TRANSACTION;

DELETE FROM dbo.SADR_ScaleItemMap
WHERE ScaleID=@ScaleID;

INSERT INTO dbo.SADR_ScaleItemMap
    (ScaleID, PluNo, ItemCode, PageNo, KeyNo)
VALUES
    (@ScaleID, @PluNo1, @ItemCode1, @PageNo1, @KeyNo1),
    (@ScaleID, @PluNo2, @ItemCode2, NULL, NULL);

UPDATE dbo.SADR_Scale
SET LastSendItem=0,
    LastSendKey=0
WHERE ScaleID=@ScaleID;

COMMIT;

قبل از ‎Commit‎ همه ‎Duplicate‎ها و محدوده ‎HotKey‎ را ‎Validate‎ کنید‎.‎ خود ‎Sadr Scales‎ همین عملیات را ‎Transactional‎ انجام می‌دهد‎.‎

۱۳. Semantic Syncداخلی — SADR_ItemSyncState و SADR_ViewPlu

SADR_ItemSyncState جدول داخلی برنامه است:

توضیح ستون
PK PluNo
‎SHA-like fingerprint‎ محتوای موثر ContentFingerprint
آخرین ‎rowversion‎ مشاهده‌شده LastObservedRowVersion
آخرین تغییر واقعی محتوایی LastSemanticRowVersion

نرم‌افزار ثالث نباید در این جدول ‎Insert/Update/Delete‎ کند‎.‎

SADR_ViewPlu نمای کالا است و علاوه بر ستون‌های SADR_Item، دو مقدار زیر را ارائه می‌دهد:

LastUpdate: نسخه ‎Semantic‎ برای تغییر واقعی محتوا‎.‎

RawLastUpdate: مقدار خام ‎rowversion‎.

برای نوشتن مستقیم ‎Integration‎، SADR_Item شفاف‌تر و پایدارتر است؛ ‎View‎ را بیشتر برای ‎Read/Compatibility‎ استفاده کنید‎.‎

۱۴. معماری ذخیره فروش در 5.2.1

هر فاکتور پذیرفته‌شده در مسیر ‎Durable‎ به شکل ‎Transactional‎ در سه نمایش ذخیره می‌شود:

۱‎. SADR_Total:‎ یک ‎Header‎ برای کل فاکتور‎.‎

۲‎. SADR_Detail:‎ یک یا چند ردیف برای اقلام فاکتور‎.‎

۳‎. SADR_Logs: Feed‎ تخت؛ یک ردیف برای هر قلم فروش‎.‎

‎Sadr Scales‎ برای ‎Duplicate detection‎، وجود کامل ‎Header/Detail/Logs‎ را بررسی می‌کند‎.‎ بنابراین نرم‌افزار ثالث نباید رکوردهای فروش را حذف یا ناقص کند‎.‎

۱۵. روش اول خواندن فروش — SADR_Logs

SADR_Logs برای نرم‌افزارهایی مناسب است که یک ‎Feed‎ ساده خط‌به‌خط می‌خواهند‎.‎

۱۵.۱ ستون‌ها

معنا ستون
‎Identity‎ و ‎Cursor‎ مناسب برای مصرف‌کننده ID
شماره ترازو؛ ‎FK‎ به ‎SADR_Scale.ScaleID‎ DeviceNo
شناسه/‎IP‎ ثبت‌شده هنگام فروش Identify
زمان فروش DateTime
شناسه فاکتور سمت ترازو/پروتکل FID
شناسه کمکی فروش SID
فروشنده/اپراتور Salesman
شماره ردیف فاکتور SubID
مبلغ ردیف TotalPrice
‎PLU‎ کالا PLU
کلاس/گروه دریافتی Class
‎Department‎ دریافتی Dept
مقدار/وزن Amount
واحد Unit
نوع لاگ/فروش LogType
مالیات Tax
متن‌های دریافتی Text1..Text4
قیمت واحد UnitPrice
شناسه همکار/کمکی پروتکل CoFID
نام کالا PLUName

Unique Key: (DeviceNo, FID, SubID).

خواندن افزایشی:

SQL
SELECT TOP (@BatchSize)
    ID, DeviceNo, Identify, [DateTime], FID, SID,
    Salesman, SubID, TotalPrice, PLU, Class, Dept,
    Amount, Unit, LogType, Tax,
    Text1, Text2, Text3, Text4,
    UnitPrice, CoFID, PLUName
FROM dbo.SADR_Logs
WHERE ID > @LastProcessedId
ORDER BY ID ASC;

در روش SADR_Logs، بهتر است نرم‌افزار مصرف‌کننده ‎Cursor‎ LastProcessedId را در دیتابیس خودش نگه دارد و رکورد ‎Sadr Scales‎ را ‎Update/Delete‎ نکند‎.‎

۱۶. روش دوم خواندن فروش — SADR_Total + SADR_Detail

این روش برای ‎POS/ERP‎هایی مناسب است که ‎Header‎ و ریز اقلام فاکتور را عیناً می‌خواهند‎.‎

۱۶.۱ Header — SADR_Total

معنا ستون
‎Identity‎ داخلی و ‎Unique‎ TotalID
شماره ترازو ScaleID
تاریخ/زمان فروش SaleDateTime
وضعیت پردازش برای مصرف‌کننده؛ پیش‌فرض ‎0‎ LableStatus
شماره رسید/فاکتور ReceiptNo
بارکد تجمیعی کل فاکتور TotalBarcode
بارکد یکتای ‎Header‎؛ ‎Primary Key‎ ItemBarcode
تعداد اقلام/تراکنش‌های فاکتور NTrans
مبلغ تخفیف فرعی SubDiscAmt
تخفیف DiscAmt
مالیات ‎A‎ AmtOfATax
مالیات ‎V‎ AmtOfVTax
مبلغ کل ثبت‌شده فاکتور PriceWTax
فروشنده/کاربر ClerkNo

۱۶.۲ Detail — SADR_Detail

معنا ستون
‎Identity‎ و ‎PK‎ DetailID
‎FK‎ به ‎Header‎ TotalID
همان بارکد تجمیعی ‎Header‎ TotalBarcode
بارکد اختصاصی ردیف ItemBarcode
شماره ردیف/‎SubID‎ TransNo
‎PLU‎ کالا PluNo
مقدار برای کالاهای وزنی ‎(Unit=3‎ در مسیر درج فعلی) Weight
تعداد برای کالاهای غیر وزنی QTY
قیمت واحد Uprice
قیمت واحد بعد از تخفیف - فیلد سازگار UpriceAfDisc
وضعیت/مقدار تخفیف سازگار StPointDiscStat
مبلغ تخفیف کل ردیف TTLPriceDiscAmt
مبلغ واقعی ردیف ActPrice
مقدار مالیات ذخیره‌شده در مسیر فعلی TaxRtNo
وضعیت پردازش خطی؛ در صورت نیاز مصرف‌کننده ItemStatus

رابطه اصلی:

SADR_Total.TotalID = SADR_Detail.TotalID

۱۷. بارکد تجمیعی فاکتور

در مسیر فعلی ‎5.2.1‎، ‎Sadr Scales‎ بارکد تجمیعی را به شکل زیر می‌سازد:

TotalBarcode = "25" + ScaleID(D3) + FID(D9)

همین مقدار عیناً در دو محل ذخیره می‌شود:

  • SADR_Total.TotalBarcode

  • SADR_Detail.TotalBarcode برای تمام ردیف‌های همان فاکتور

بنابراین اگر ‎POS‎ بارکد تجمیعی چاپ‌شده در انتهای فاکتور را اسکن کند، می‌تواند مستقیم ‎Header‎ و ‎Detail‎ را بازیابی کند‎.‎

SQL
SELECT
    t.TotalID, t.ScaleID, t.SaleDateTime,
    t.ReceiptNo, t.TotalBarcode, t.ItemBarcode,
    t.NTrans, t.PriceWTax, t.ClerkNo, t.LableStatus,
    d.DetailID, d.TransNo, d.PluNo,
    d.Weight, d.QTY, d.Uprice, d.ActPrice,
    d.ItemBarcode AS DetailItemBarcode,
    d.ItemStatus
FROM dbo.SADR_Total t
LEFT JOIN dbo.SADR_Detail d
    ON d.TotalID = t.TotalID
WHERE t.TotalBarcode = @ScannedBarcode
ORDER BY d.DetailID;

برای فیلتر دقیق‌تر در محیط چند ترازو می‌توانید ScaleID را نیز اضافه کنید‎.‎

SADR_Total.ItemBarcode با TotalBarcode فرق دارد‎.‎ برای جست‌وجوی بارکد تجمیعی انتهای فاکتور از `TotalBarcode` استفاده کنید‎.‎

۱۸. جلوگیری از خواندن دوباره فروش — Status/Acknowledgement

‎Sadr Scales‎ هنگام درج ‎Header‎ مقدار LableStatus را به‌صورت پیش‌فرض 0 می‌گذارد و ‎Detail‎ با ItemStatus=0 درج می‌شود‎.‎

در معماری این سند، هر نصب ‎Sadr Scales‎ یک نرم‌افزار فروشگاهی/حسابداری مقصد دارد. برای روش ساخت‌یافته می‌توان قرارداد زیر را برای وضعیت پردازش همان مقصد استفاده کرد:

  • LableStatus = 0: فاکتور هنوز توسط نرم‌افزار مصرف‌کننده پردازش نشده است‎.‎

  • LableStatus = 1: فاکتور با موفقیت مصرف/ثبت شده است‎.‎

  • ItemStatus = 0/1: در صورت نیاز همین مفهوم در سطح ردیف‎.‎

خواندن فروش و ‎Ack‎ را در دو مرحله کوتاه انجام دهید؛ تراکنش پایگاه داده ‎Sadr Scales‎ را هنگام ثبت فاکتور در سیستم مقصد باز نگه ندارید.

SQL
-- Step 1: read the next unprocessed invoice.
DECLARE @TotalID int;

SELECT TOP (1)
    @TotalID = TotalID
FROM dbo.SADR_Total
WHERE ISNULL(LableStatus, 0) = 0
ORDER BY TotalID;

IF @TotalID IS NOT NULL
BEGIN
    SELECT *
    FROM dbo.SADR_Total
    WHERE TotalID = @TotalID;

    SELECT *
    FROM dbo.SADR_Detail
    WHERE TotalID = @TotalID
    ORDER BY DetailID;
END;
SQL
-- Step 2: run only after the destination commit succeeds.
SET XACT_ABORT ON;
BEGIN TRANSACTION;

UPDATE dbo.SADR_Total
SET LableStatus = 1
WHERE TotalID = @TotalID
  AND ISNULL(LableStatus, 0) = 0;

UPDATE dbo.SADR_Detail
SET ItemStatus = 1
WHERE TotalID = @TotalID
  AND ISNULL(ItemStatus, 0) = 0;

COMMIT;

برای اسکن بارکد نیز همین ترتیب را رعایت کنید: ابتدا فاکتور را در ‎POS‎ ثبت و ‎Commit‎ کنید، سپس ‎TotalID‎ همان فاکتور را ‎Ack‎ کنید. ‎LableStatus/ItemStatus‎ وضعیت همان نرم‌افزار مقصد این نصب هستند و برای ‎Cursor‎ داخلی دریافت از ترازو استفاده نمی‌شوند.

۱۹. دریافت فاکتور کامل بر اساس ترازو و FID

SADR_Logs با (DeviceNo, FID, SubID) یکتا است‎.‎ در ‎Structured Sales‎، TotalBarcode از ScaleID+FID ساخته می‌شود‎.‎ بنابراین برای یک ترازو و ‎FID‎ می‌توان سه نمایش را تطبیق داد‎.‎

SQL
DECLARE @TotalBarcode varchar(50) =
    '25' + RIGHT('000' + CAST(@ScaleID AS varchar(10)), 3)
         + RIGHT('000000000' + CAST(@FID AS varchar(20)), 9);

SELECT *
FROM dbo.SADR_Total
WHERE ScaleID=@ScaleID AND TotalBarcode=@TotalBarcode;

SELECT d.*
FROM dbo.SADR_Detail d
INNER JOIN dbo.SADR_Total t ON t.TotalID=d.TotalID
WHERE t.ScaleID=@ScaleID AND t.TotalBarcode=@TotalBarcode
ORDER BY d.DetailID;

SELECT *
FROM dbo.SADR_Logs
WHERE DeviceNo=@ScaleID AND FID=@FID
ORDER BY SubID;

این سه ‎Query‎ برای عیب‌یابی ‎Integration‎ و کنترل کامل‌بودن فاکتور بسیار مفیدند‎.‎

۲۰. JHMA_Logs — سازگاری نسخه‌های قدیمی

dbo.JHMA_Logs در ‎Schema‎ فعلی یک View روی dbo.SADR_Logs است، نه جدول اصلی فروش‎.‎

برای ‎Integration‎ جدید از ‎SADR_Logs‎ استفاده کنید‎. JHMA_Logs‎ فقط برای سازگاری نرم‌افزارهای قدیمی که نام قبلی را انتظار دارند نگه داشته شده است‎.‎

۲۱. تاریخچه قیمت — SADR_PriceLog

ساختار:

توضیح ستون
Identity ID
PLU PluNo
بارکد/ایندکس IndexBarcode
نام کالا PluName
قیمت قبلی LastPrice
قیمت جدید NewPrice
زمان تغییر DateTime
کاربر؛ پیش‌فرض ‎Admin‎ User

این جدول در ‎UI‎ به‌عنوان ‎Price Log‎ خوانده می‌شود‎.‎ برای ‎Integration‎ عمومی، تغییر قیمت اصلی را روی SADR_Item.UnitPrice انجام دهید؛ SADR_PriceLog را جدول ‎Master‎ قیمت تلقی نکنید‎.‎

۲۲. Viewهای LastUpdate

SADR_ViewPlu

نمای کالا با:

  • LastUpdate: تغییر ‎Semantic.‎

  • RawLastUpdate: ‎rowversion‎ خام‎.‎

SADR_ViewKey

نمای SADR_KeyAssignment با:

  • LastUpdate = CONVERT(bigint, TimeStamp)

این ‎View‎ها برای تشخیص تغییر و سازگاری داخلی مهم‌اند‎.‎ نرم‌افزار ثالث نباید مقدار LastUpdate را بنویسد‎.‎

۲۳. Cursorها و فیلدهای Runtime که نباید آزادانه تغییر کنند

قاعده مالک فیلد
فقط وضعیت اتصال؛ ‎Enabled‎ نیست Runtime SADR_Scale.Status
فقط هنگام تغییر ‎Group/Map‎ طبق الگوی برنامه ‎Reset‎ به ‎0‎ Runtime/Sync LastSendItem
فقط هنگام تغییر ‎Key/Map‎ طبق الگوی برنامه ‎Reset‎ به ‎0‎ Runtime/Sync LastSendKey
‎Cursor‎ دریافت؛ دستکاری آزاد ممنوع Runtime LastReceiveFID
‎Flag‎ هماهنگی تنظیمات Runtime SendScaleDetail
‎Flag‎ هماهنگی تنظیمات Runtime GetScaleDetail
معمولاً از دستگاه تکمیل می‌شوند Hardware/Runtime Mac, Version
کاملاً داخلی Runtime SADR_ItemSyncState.*
هرگز دستی ننویسید SQL Server TimeStamp/rowversion

۲۴. عملیات حذف و خطر Cascade

حذف ترازو

حذف فیزیکی ‎Scale‎ در مسیر خود برنامه عمداً موارد زیر را پاک می‌کند:

  • SADR_Logs مربوط به ترازو‎.‎

  • SADR_Detail مربوط به فاکتورهای ترازو‎.‎

  • SADR_Total مربوط به ترازو‎.‎

  • SADR_ScaleItemMap

  • SADR_ScaleItemClass

  • خود SADR_Scale.

بنابراین حذف ‎Scale‎ یک عملیات پاک‌سازی داده است، نه غیرفعال‌سازی‎.‎

حذف کالا

به دلیل ‎FK‎ SADR_ScaleItemMap.PluNo -> SADR_Item.PluNo ON DELETE CASCADE، حذف فیزیکی کالا نگاشت‌های اختصاصی آن را نیز حذف می‌کند‎.‎

حذف Header فاکتور

حذف SADR_Total، ردیف‌های SADR_Detail همان ‎TotalID‎ را ‎Cascade‎ حذف می‌کند‎.‎

۲۵. سناریوی کامل: ساخت گروه، ترازو، کالا و کلید سریع

SQL
SET XACT_ABORT ON;
BEGIN TRANSACTION;

-- 1) Group
IF NOT EXISTS (SELECT 1 FROM dbo.SADR_ItemClass WHERE ItemClassCode='10')
    INSERT INTO dbo.SADR_ItemClass(ItemClassCode, ItemClassName, Descriptions)
    VALUES('10', N'Fruit', N'Fruit group');

-- 2) Store
IF NOT EXISTS (SELECT 1 FROM dbo.SADR_Store WHERE StoreCode='1')
    INSERT INTO dbo.SADR_Store(StoreCode, StoreName, Descriptions)
    VALUES('1', N'Main Store', N'');

-- 3) Scale
IF NOT EXISTS (SELECT 1 FROM dbo.SADR_Scale WHERE ScaleID=1 OR ScaleIP='192.168.1.50')
BEGIN
    INSERT INTO dbo.SADR_Scale
    (
        ScaleID, ScaleIP, Port, Category,
        StoreCode, StoreName, ItemClassCode, DeviceName,
        HotKeyCountPerPage, HotKeyPageCount,
        AutoSendItems, AutoGetInvoice, Used
    )
    VALUES
    (
        1, '192.168.1.50', 33581, 'LSG',
        '1', N'Main Store', '10', N'Checkout Scale 1',
        63, 3,
        1, 0, 1
    );

    INSERT INTO dbo.SADR_ScaleItemClass(ScaleID, ItemClassCode)
    VALUES(1, '10');
END;

-- 4) Item
IF NOT EXISTS (SELECT 1 FROM dbo.SADR_Item WHERE PluNo=1001)
    INSERT INTO dbo.SADR_Item
        (ItemClassCode, PluNo, PluName, PluUnit, UnitPrice, DeleteFlag)
    VALUES
        ('10', 1001, N'Apple', 3, 150000, 0);
ELSE
    UPDATE dbo.SADR_Item
    SET ItemClassCode='10', PluName=N'Apple',
        PluUnit=3, UnitPrice=150000, DeleteFlag=0
    WHERE PluNo=1001;

-- 5) Group HotKey: page 0 key 1
IF EXISTS
(
    SELECT 1 FROM dbo.SADR_KeyAssignment
    WHERE ItemClassCode='10' AND PageNo=0 AND KeyNo=1
)
    UPDATE dbo.SADR_KeyAssignment
    SET PluNo=1001
    WHERE ItemClassCode='10' AND PageNo=0 AND KeyNo=1;
ELSE
    INSERT INTO dbo.SADR_KeyAssignment(ItemClassCode,PageNo,KeyNo,PluNo)
    VALUES('10',0,1,1001);

UPDATE dbo.SADR_Scale
SET LastSendItem=0, LastSendKey=0
WHERE ScaleID=1;

COMMIT;

بعد از این تغییرات، اگر ‎Sadr Scales‎ در حال اجراست ‎Registry/Connection‎ را ‎Reload/Restart‎ کنید تا تنظیمات ترازو قطعی اعمال شوند‎.‎

۲۶. سناریوی کامل: دریافت و Ack فروش اسکن‌شده

SQL
-- Step 1: read the scanned invoice.
DECLARE @TotalID int;

SELECT TOP (1)
    @TotalID = TotalID
FROM dbo.SADR_Total
WHERE TotalBarcode = @ScannedBarcode;

IF @TotalID IS NULL
    THROW 50001, 'Invoice barcode not found', 1;

SELECT *
FROM dbo.SADR_Total
WHERE TotalID = @TotalID;

SELECT *
FROM dbo.SADR_Detail
WHERE TotalID = @TotalID
ORDER BY DetailID;

فاکتور را با شناسه یکتای خود در سیستم مقصد به‌صورت ‎Idempotent‎ ثبت کنید. فقط پس از ‎Commit‎ موفق مقصد، وضعیت پردازش را در یک تراکنش کوتاه در پایگاه داده ‎Sadr Scales‎ به‌روزرسانی کنید:

SQL
SET XACT_ABORT ON;
BEGIN TRANSACTION;

UPDATE dbo.SADR_Total
SET LableStatus = 1
WHERE TotalID = @TotalID
  AND ISNULL(LableStatus, 0) = 0;

UPDATE dbo.SADR_Detail
SET ItemStatus = 1
WHERE TotalID = @TotalID
  AND ISNULL(ItemStatus, 0) = 0;

COMMIT;

۲۷. کنترل صحت Schema قبل از شروع Integration

SQL
IF OBJECT_ID(N'dbo.SADR_ItemClass', N'U') IS NULL THROW 50001, 'SADR_ItemClass missing', 1;
IF OBJECT_ID(N'dbo.SADR_Store', N'U') IS NULL THROW 50002, 'SADR_Store missing', 1;
IF OBJECT_ID(N'dbo.SADR_Scale', N'U') IS NULL THROW 50003, 'SADR_Scale missing', 1;
IF OBJECT_ID(N'dbo.SADR_ScaleItemClass', N'U') IS NULL THROW 50004, 'SADR_ScaleItemClass missing', 1;
IF OBJECT_ID(N'dbo.SADR_Item', N'U') IS NULL THROW 50005, 'SADR_Item missing', 1;
IF OBJECT_ID(N'dbo.SADR_KeyAssignment', N'U') IS NULL THROW 50006, 'SADR_KeyAssignment missing', 1;
IF OBJECT_ID(N'dbo.SADR_ScaleItemMap', N'U') IS NULL THROW 50007, 'SADR_ScaleItemMap missing', 1;
IF OBJECT_ID(N'dbo.SADR_Total', N'U') IS NULL THROW 50008, 'SADR_Total missing', 1;
IF OBJECT_ID(N'dbo.SADR_Detail', N'U') IS NULL THROW 50009, 'SADR_Detail missing', 1;
IF OBJECT_ID(N'dbo.SADR_Logs', N'U') IS NULL THROW 50010, 'SADR_Logs missing', 1;

اگر ‎Database‎ قدیمی است، ابتدا اجازه دهید ‎Sadr Scales 5.2.1 Schema migration‎ خود را اجرا کند؛ ‎Integration‎ نباید خودش ‎Constraint‎های داخلی را حذف یا بازسازی کند‎.‎

۲۸. سطح دسترسی پیشنهادی SQL

برای نرم‌افزار ثالث از حساب ‎sa‎ استفاده نکنید و ‎Credential‎ واقعی را در ‎Source‎، فایل نمونه یا ‎Log‎ قرار ندهید‎.‎ حداقل دسترسی لازم را بدهید:

• ‎SELECT‎ روی ‎Object‎های موردنیاز‎.‎

• ‎INSERT/UPDATE‎ روی ‎Group/Store/Scale/Item/Key/Map‎ فقط اگر نرم‌افزار واقعاً این قابلیت‌ها را دارد‎.‎

• ‎UPDATE‎ محدود روی SADR_Total.LableStatus و در صورت نیاز SADR_Detail.ItemStatus.

• بدون ‎DELETE‎ روی ‎Sales‎ برای ‎Integration‎ عادی‎.‎

• بدون ‎Write‎ روی SADR_ItemSyncState.

در محیط حساس بهتر است عملیات ‎Write‎ از ‎Stored Procedure‎های کنترل‌شده انجام شود تا ‎Permission‎ مستقیم جدول محدود بماند‎.‎

۲۹. سازگاری و نسخه‌بندی قرارداد

این سند قرارداد پایگاه داده و یکپارچه‌سازی ‎Sadr Scales 5.2.1‎ با ‎SQL Contract v1‎ را شرح می‌دهد‎.‎ نرم‌افزار ‎Integration‎ باید نسخه قرارداد مورد انتظار خود را ثبت کند و تغییر ‎Schema‎ یا ‎Contract‎ را بدون بررسی سازگاری وارد محیط مشتری نکند‎.‎

‎Integration‎ باید هنگام ‎Startup‎ نسخه قرارداد مورد انتظار خود را کنترل کند و قبل از استفاده از ستون/جدول جدید، وجود آن را با OBJECT_ID و COL_LENGTH بررسی کند‎.‎

‎Schema‎ داخلی را صرفاً بر اساس حدس نسخه تغییر ندهید‎.‎

۳۰. چک‌لیست برنامه‌نویس

  • [ ] ‎Connection String‎ از تنظیمات امن خوانده می‌شود و داخل ‎Source‎ ثبت نشده است‎.‎

  • [ ] گروه و شعبه قبل از ‎Master‎های وابسته ساخته می‌شوند‎.‎

  • [ ] ‎ScaleID‎ و ‎ScaleIP‎ تکراری نیستند‎.‎

  • [ ] فعال‌سازی ‎Scale‎ سقف لایسنس را دور نمی‌زند‎.‎

  • [ ] غیرفعال‌سازی با Used=0 انجام می‌شود‎.‎

  • [ ] گروه اصلی ‎Scale‎ در SADR_ScaleItemClass نیز وجود دارد‎.‎

  • [ ] PluNo غیرصفر و یکتا است‎.‎

  • [ ] TimeStamp, LastUpdate, ItemSyncState دستی نوشته نمی‌شوند‎.‎

  • [ ] ‎KeyAssignment‎ فقط به ‎PLU‎ معتبر اشاره می‌کند‎.‎

  • [ ] ‎ScaleItemMap Duplicate ItemCode/HotKey‎ ندارد و داخل ‎Layout‎ ترازو است‎.‎

  • [ ] تغییر ‎Group/Map/Key Cursor‎ ارسال مرتبط را طبق الگوی برنامه ‎Reset‎ می‌کند‎.‎

  • [ ] فروش از SADR_Logs با ‎Cursor‎ مستقل یا از ‎Total/Detail‎ با ‎Ack‎ خوانده می‌شود‎.‎

  • [ ] TotalBarcode برای اسکن فاکتور استفاده می‌شود، نه ItemBarcode Header.

  • [ ] ‎Ack‎ فقط بعد از ثبت موفق فروش در سیستم مقصد به ‎1‎ تغییر می‌کند‎.‎

  • [ ] هیچ ‎DELETE‎ عادی روی ‎Scale/Sales‎ انجام نمی‌شود‎.‎

  • [ ] عملیات چندجدولی ‎Transactional‎ و ‎Idempotent‎ هستند‎.‎

ضمیمه A. نمونه مرجع C# برای .NET Framework 4.x

کدهای این ضمیمه نمونه مرجع برای پیاده‌سازی ‎SQL Contract v1‎ هستند‎.‎ همه ‎Query‎ها ‎Parameterized‎ هستند و از ‎ADO.NET‎ استاندارد استفاده می‌کنند‎. Credential‎ واقعی مشتری را داخل ‎Source‎ قرار ندهید‎.‎

نکته: این نمونه‌ها مستقیماً با ‎SQL Server‎ کار می‌کنند و هیچ منطق پروتکل ترازو را پیاده‌سازی نمی‌کنند‎.‎ مدیریت ارتباط با ترازو بر عهده ‎Sadr Scales‎ است‎.‎

A.1 اتصال و کنترل Schema

C#
using System;
using System.Data;
using System.Data.SqlClient;

public static class SadrSchema
{
    public static SqlConnection Open(string connectionString)
    {
        SqlConnection connection = new SqlConnection(connectionString);
        connection.Open();
        return connection;
    }

    public static void Validate(SqlConnection connection)
    {
        const string sql = @"
IF OBJECT_ID(N'dbo.SADR_ItemClass', N'U') IS NULL
    THROW 50001, 'SADR_ItemClass missing', 1;
IF OBJECT_ID(N'dbo.SADR_Store', N'U') IS NULL
    THROW 50002, 'SADR_Store missing', 1;
IF OBJECT_ID(N'dbo.SADR_Scale', N'U') IS NULL
    THROW 50003, 'SADR_Scale missing', 1;
IF OBJECT_ID(N'dbo.SADR_ScaleItemClass', N'U') IS NULL
    THROW 50004, 'SADR_ScaleItemClass missing', 1;
IF OBJECT_ID(N'dbo.SADR_Item', N'U') IS NULL
    THROW 50005, 'SADR_Item missing', 1;
IF OBJECT_ID(N'dbo.SADR_KeyAssignment', N'U') IS NULL
    THROW 50006, 'SADR_KeyAssignment missing', 1;
IF OBJECT_ID(N'dbo.SADR_ScaleItemMap', N'U') IS NULL
    THROW 50007, 'SADR_ScaleItemMap missing', 1;
IF OBJECT_ID(N'dbo.SADR_Total', N'U') IS NULL
    THROW 50008, 'SADR_Total missing', 1;
IF OBJECT_ID(N'dbo.SADR_Detail', N'U') IS NULL
    THROW 50009, 'SADR_Detail missing', 1;
IF OBJECT_ID(N'dbo.SADR_Logs', N'U') IS NULL
    THROW 50010, 'SADR_Logs missing', 1;";

        using (SqlCommand command = new SqlCommand(sql, connection))
        {
            command.CommandTimeout = 30;
            command.ExecuteNonQuery();
        }
    }
}

A.2 مدل داده کالا

C#
public sealed class SadrItem
{
    public string ItemClassCode { get; set; }
    public int PluNo { get; set; }
    public int PluUnit { get; set; }
    public int UnitPrice { get; set; }
    public int PrintFormat { get; set; }
    public int PluCost { get; set; }
    public int BarFormat { get; set; }
    public int BarFlags { get; set; }
    public string ItemCode { get; set; }
    public string IndexBarcode { get; set; }
    public double Tare { get; set; }
    public int ShelfDate { get; set; }
    public int ShelfDatePrint { get; set; }
    public int SaleDatePrint { get; set; }
    public int SaleTimePrint { get; set; }
    public int OnlyTare { get; set; }
    public double TaxRate { get; set; }
    public string PluName { get; set; }
    public string Text1 { get; set; }
    public string Text2 { get; set; }
    public string Text3 { get; set; }
    public string Text4 { get; set; }
    public string Text5 { get; set; }
    public string Text6 { get; set; }
    public string Text7 { get; set; }
    public int DeleteFlag { get; set; }
}

A.3 ایجاد یا ویرایش گروه کالا

C#
public static void UpsertItemClass(
    SqlConnection connection,
    string code,
    string name,
    string description)
{
    const string sql = @"
IF NOT EXISTS
(
    SELECT 1
    FROM dbo.SADR_ItemClass
    WHERE ItemClassCode = @Code
)
BEGIN
    INSERT INTO dbo.SADR_ItemClass
        (ItemClassCode, ItemClassName, Descriptions)
    VALUES
        (@Code, @Name, @Description);
END
ELSE
BEGIN
    UPDATE dbo.SADR_ItemClass
    SET ItemClassName = @Name,
        Descriptions = @Description
    WHERE ItemClassCode = @Code;
END;";

    using (SqlCommand command = new SqlCommand(sql, connection))
    {
        command.Parameters.Add("@Code", SqlDbType.VarChar, 50).Value = code;
        command.Parameters.Add("@Name", SqlDbType.NVarChar, 100).Value =
            (object)name ?? DBNull.Value;
        command.Parameters.Add("@Description", SqlDbType.NVarChar, 150).Value =
            (object)description ?? DBNull.Value;
        command.ExecuteNonQuery();
    }
}

A.4 Upsert کامل کالا داخل Transaction

C#
public static void UpsertItem(SqlConnection connection, SadrItem item)
{
    const string sql = @"
IF NOT EXISTS (SELECT 1 FROM dbo.SADR_Item WHERE PluNo=@PluNo)
BEGIN
    INSERT INTO dbo.SADR_Item
    (
        ItemClassCode, PluNo, PluUnit, UnitPrice,
        PrintFormat, PluCost, BarFormat, BarFlags,
        ItemCode, IndexBarcode, Tare,
        ShelfDate, ShelfDatePrint, SaleDatePrint, SaleTimePrint,
        OnlyTare, TaxRate, PluName,
        Text1, Text2, Text3, Text4, Text5, Text6, Text7,
        DeleteFlag
    )
    VALUES
    (
        @ItemClassCode, @PluNo, @PluUnit, @UnitPrice,
        @PrintFormat, @PluCost, @BarFormat, @BarFlags,
        @ItemCode, @IndexBarcode, @Tare,
        @ShelfDate, @ShelfDatePrint, @SaleDatePrint, @SaleTimePrint,
        @OnlyTare, @TaxRate, @PluName,
        @Text1, @Text2, @Text3, @Text4, @Text5, @Text6, @Text7,
        @DeleteFlag
    );
END
ELSE
BEGIN
    UPDATE dbo.SADR_Item
    SET ItemClassCode=@ItemClassCode,
        PluUnit=@PluUnit,
        UnitPrice=@UnitPrice,
        PrintFormat=@PrintFormat,
        PluCost=@PluCost,
        BarFormat=@BarFormat,
        BarFlags=@BarFlags,
        ItemCode=@ItemCode,
        IndexBarcode=@IndexBarcode,
        Tare=@Tare,
        ShelfDate=@ShelfDate,
        ShelfDatePrint=@ShelfDatePrint,
        SaleDatePrint=@SaleDatePrint,
        SaleTimePrint=@SaleTimePrint,
        OnlyTare=@OnlyTare,
        TaxRate=@TaxRate,
        PluName=@PluName,
        Text1=@Text1, Text2=@Text2, Text3=@Text3, Text4=@Text4,
        Text5=@Text5, Text6=@Text6, Text7=@Text7,
        DeleteFlag=@DeleteFlag
    WHERE PluNo=@PluNo;
END;";

    using (SqlTransaction tx = connection.BeginTransaction())
    using (SqlCommand command = new SqlCommand(sql, connection, tx))
    {
        command.Parameters.Add("@ItemClassCode", SqlDbType.VarChar, 50).Value = item.ItemClassCode;
        command.Parameters.Add("@PluNo", SqlDbType.Int).Value = item.PluNo;
        command.Parameters.Add("@PluUnit", SqlDbType.Int).Value = item.PluUnit;
        command.Parameters.Add("@UnitPrice", SqlDbType.Int).Value = item.UnitPrice;
        command.Parameters.Add("@PrintFormat", SqlDbType.Int).Value = item.PrintFormat;
        command.Parameters.Add("@PluCost", SqlDbType.Int).Value = item.PluCost;
        command.Parameters.Add("@BarFormat", SqlDbType.Int).Value = item.BarFormat;
        command.Parameters.Add("@BarFlags", SqlDbType.Int).Value = item.BarFlags;
        command.Parameters.Add("@ItemCode", SqlDbType.VarChar, 10).Value =
            (object)item.ItemCode ?? DBNull.Value;
        command.Parameters.Add("@IndexBarcode", SqlDbType.VarChar, 50).Value =
            (object)item.IndexBarcode ?? DBNull.Value;
        command.Parameters.Add("@Tare", SqlDbType.Float).Value = item.Tare;
        command.Parameters.Add("@ShelfDate", SqlDbType.Int).Value = item.ShelfDate;
        command.Parameters.Add("@ShelfDatePrint", SqlDbType.Int).Value = item.ShelfDatePrint;
        command.Parameters.Add("@SaleDatePrint", SqlDbType.Int).Value = item.SaleDatePrint;
        command.Parameters.Add("@SaleTimePrint", SqlDbType.Int).Value = item.SaleTimePrint;
        command.Parameters.Add("@OnlyTare", SqlDbType.Int).Value = item.OnlyTare;
        command.Parameters.Add("@TaxRate", SqlDbType.Float).Value = item.TaxRate;
        command.Parameters.Add("@PluName", SqlDbType.NVarChar, 100).Value =
            (object)item.PluName ?? DBNull.Value;
        command.Parameters.Add("@DeleteFlag", SqlDbType.Int).Value = item.DeleteFlag;

        string[] values = { item.Text1, item.Text2, item.Text3, item.Text4,
                            item.Text5, item.Text6, item.Text7 };
        for (int i = 0; i < values.Length; i++)
        {
            command.Parameters.Add("@Text" + (i + 1), SqlDbType.NVarChar, 100).Value =
                (object)values[i] ?? DBNull.Value;
        }

        command.ExecuteNonQuery();
        tx.Commit();
    }
}
قاعده مهم:
برای عملکرد بهتر، ‎UPDATE‎ را فقط در صورت
تغییر واقعی محتوا انجام دهید‎. rowversion‎ خام ممکن است با ‎UPDATE‎ دوباره
تغییر کند، اما ‎Semantic Change‎ توسط ‎Sadr Scales‎ بر اساس محتوای مؤثر
تشخیص داده می‌شود‎.‎

A.5 خواندن افزایشی فروش از SADR_Logs

C#
public static DataTable ReadSalesAfterId(
    SqlConnection connection,
    long lastProcessedId,
    int batchSize)
{
    const string sql = @"
SELECT TOP (@BatchSize)
    ID, DeviceNo, Identify, [DateTime], FID, SID,
    Salesman, SubID, TotalPrice, PLU, Class, Dept,
    Amount, Unit, LogType, Tax,
    Text1, Text2, Text3, Text4,
    UnitPrice, CoFID, PLUName
FROM dbo.SADR_Logs
WHERE ID > @LastProcessedId
ORDER BY ID ASC;";

    using (SqlCommand command = new SqlCommand(sql, connection))
    {
        command.Parameters.Add("@BatchSize", SqlDbType.Int).Value = batchSize;
        command.Parameters.Add("@LastProcessedId", SqlDbType.BigInt).Value = lastProcessedId;

        using (SqlDataAdapter adapter = new SqlDataAdapter(command))
        {
            DataTable table = new DataTable();
            adapter.Fill(table);
            return table;
        }
    }
}

پس از ثبت موفق هر ‎Batch‎ در سیستم مقصد، بزرگ‌ترین ‎ID‎ ثبت‌شده را در پایگاه داده خود نرم‌افزار مقصد نگه‌دارید‎.‎ رکوردهای ‎SADR_Logs‎ را برای مدیریت ‎Cursor‎ تغییر ندهید‎.‎

A.6 دریافت فاکتور کامل با TotalBarcode

C#
public static DataSet ReadInvoiceByBarcode(
    SqlConnection connection,
    string totalBarcode)
{
    const string headerSql = @"
SELECT *
FROM dbo.SADR_Total
WHERE TotalBarcode=@TotalBarcode;";

    const string detailSql = @"
SELECT d.*
FROM dbo.SADR_Detail d
INNER JOIN dbo.SADR_Total t ON t.TotalID=d.TotalID
WHERE t.TotalBarcode=@TotalBarcode
ORDER BY d.DetailID;";

    DataSet result = new DataSet();

    using (SqlCommand header = new SqlCommand(headerSql, connection))
    {
        header.Parameters.Add("@TotalBarcode", SqlDbType.VarChar, 50).Value = totalBarcode;
        using (SqlDataAdapter adapter = new SqlDataAdapter(header))
            adapter.Fill(result, "Header");
    }

    using (SqlCommand detail = new SqlCommand(detailSql, connection))
    {
        detail.Parameters.Add("@TotalBarcode", SqlDbType.VarChar, 50).Value = totalBarcode;
        using (SqlDataAdapter adapter = new SqlDataAdapter(detail))
            adapter.Fill(result, "Detail");
    }

    return result;
}

A.7 Ack فاکتور

C#
public static void AcknowledgeInvoice(
    SqlConnection connection,
    int totalId)
{
    const string sql = @"
UPDATE dbo.SADR_Total
SET LableStatus=1
WHERE TotalID=@TotalID
  AND ISNULL(LableStatus,0)=0;

UPDATE dbo.SADR_Detail
SET ItemStatus=1
WHERE TotalID=@TotalID
  AND ISNULL(ItemStatus,0)=0;";

    using (SqlTransaction tx = connection.BeginTransaction())
    using (SqlCommand command = new SqlCommand(sql, connection, tx))
    {
        command.Parameters.Add("@TotalID", SqlDbType.Int).Value = totalId;
        command.ExecuteNonQuery();
        tx.Commit();
    }
}
هشدار مالی:
‎Ack‎ را فقط بعد از ثبت موفق و ‎Commit‎
فاکتور در سیستم مقصد انجام دهید. در صورت قطع ارتباط بین ثبت مقصد و ‎Ack‎،
ثبت مقصد باید ‎Idempotent‎ باشد تا پردازش دوباره باعث فروش تکراری
نشود.

A.8 نمونه جریان ساده برنامه

C#
static void Main()
{
    string connectionString = LoadConnectionStringFromSecureSettings();
    using (SqlConnection connection = SadrSchema.Open(connectionString))
    {
        SadrSchema.Validate(connection);
        UpsertItemClass(connection, "10", "Fruit", "Fruit group");
        DataTable sales = ReadSalesAfterId(connection, 0, 100);
        foreach (DataRow row in sales.Rows)
        {
            // 1) Map row to the destination model.
            // 2) Save it idempotently in the destination database.
            // 3) Persist the last successfully processed SADR_Logs.ID.
        }
    }
}

ضمیمه B. پیاده‌سازی همین قرارداد در زبان‌های دیگر

‎SQL Contract‎ به زبان برنامه‌نویسی وابسته نیست‎.‎ اگر نرم‌افزار مقصد با ‎C#/.NET‎ نوشته نشده است، همان قواعد این سند باید در ‎Driver‎ یا کتابخانه ‎SQL‎ زبان مقصد رعایت شوند‎.‎

قاعده رفتار لازم
Parameterized Query هیچ مقدار ورودی با الحاق رشته داخل ‎SQL‎ ساخته نشود‎.‎
Transaction عملیات چندجدولی مانند ‎Scale + ScaleItemClass‎ یا ‎Ack Header + Detail‎ اتمیک باشد؛ تراکنش پایگاه داده هنگام ثبت در سیستم خارجی باز نگه داشته نشود.
Idempotency اجرای دوباره ‎Import‎ یا دریافت فروش باعث رکورد مالی تکراری نشود‎.‎
‎Cursor‎ فروش ‎LastProcessedId‎ یا ‎State‎ مصرف‌کننده در سیستم مقصد نگه‌داری شود‎.‎
Runtime Fields ‎Status‎، ‎LastReceiveFID‎، ‎rowversion‎ و ‎SADR_ItemSyncState‎ آزادانه نوشته نشوند‎.‎
Scale Disable برای غیرفعال‌سازی از ‎Used=0‎ استفاده شود؛ ‎DELETE‎ معادل ‎Disable‎ نیست‎.‎
Security ‎Credential‎ در ‎Source/Log‎ ذخیره نشود و حساب ‎SQL‎ حداقل ‎Permission‎ لازم را داشته باشد‎.‎
Compatibility قبل از استفاده از ‎Object‎ یا ستون، وجود ‎Schema‎ مورد انتظار کنترل شود‎.‎

نمونه‌های ‎C#‎ ضمیمه ‎A‎ را می‌توان به‌عنوان مرجع رفتاری دید: نام جدول‌ها، ترتیب ‎Transaction‎، ‎Parameter‎ها، ‎Cursor‎ فروش و ‎Ack‎ باید در زبان مقصد همان معنا را حفظ کنند‎.‎

چک سریع قبل از تحویل Integration

• [ ] ‎Schema‎ مورد انتظار روی دیتابیس مشتری کنترل شده است‎.‎

• [ ] هیچ ‎Credential‎ واقعی داخل ‎Source‎ یا ‎Log‎ وجود ندارد‎.‎

• [ ] همه ‎Query‎ها ‎Parameterized‎ هستند‎.‎

• [ ] نوشتن چندجدولی ‎Transactional‎ است‎.‎

• [ ] ‎Import‎ کالا در اجرای دوباره نتیجه تکراری یا ناسازگار ایجاد نمی‌کند‎.‎

• [ ] ‎Cursor‎ فروش فقط بعد از ثبت موفق مقصد جلو می‌رود‎.‎

• [ ] ‎Ack‎ فاکتور فقط بعد از ‎Commit‎ مقصد انجام می‌شود‎.‎

• [ ] ‎DELETE‎ روی ‎Scale/Sales‎ در عملیات عادی وجود ندارد‎.‎

• [ ] فیلدهای ‎Runtime/Internal‎ خارج از قرارداد تغییر داده نمی‌شوند‎.‎