# Sales Order

## Sales Order's Database

<table><thead><tr><th>UI Name</th><th>Database</th><th>Type</th><th>Remarks</th></tr></thead><tbody><tr><td>S/O No</td><td><pre><code>docNo
</code></pre></td><td><strong><code>String</code></strong></td><td><p>Avoid using the same <strong><code>S/O No</code></strong> to prevent overwrite.</p><p></p><p>E.g.: <code>SO-123456</code></p></td></tr><tr><td>S/O Key</td><td><pre><code>docKey
</code></pre></td><td><strong><code>Number</code></strong></td><td>E.g.: <code>123456</code></td></tr><tr><td>Debtor</td><td><pre><code>debtorCode
</code></pre></td><td><strong><code>String</code></strong></td><td><p><strong><code>Debtor</code></strong> must match existing <strong>debtor code</strong>, and they must be <strong>active</strong> state.</p><p></p><p>E.g.: <code>400-D001</code></p></td></tr><tr><td>Name</td><td><pre><code>debtorName
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>JOHN DOE</code></td></tr><tr><td>Address [Line 1]</td><td><pre><code>invAddr1
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>123 MAIN ST,</code></td></tr><tr><td>Address [Line 2]</td><td><pre><code>invAddr2
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>APT 4B,</code></td></tr><tr><td>Address [Line 3]</td><td><pre><code>invAddr3
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>NEW YORK, NY 10001</code></td></tr><tr><td>Delivery Address [Line 1]</td><td><pre><code>DeliverAddr1
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>456 SECOND ST,</code></td></tr><tr><td>Delivery Address [Line 2]</td><td><pre><code>DeliverAddr2
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>SUITE 5A,</code></td></tr><tr><td>Delivery Address [Line 3]</td><td><pre><code>DeliverAddr3
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>LOS ANGELES, CA 90001</code></td></tr><tr><td>Sales Location</td><td><pre><code>salesLocation
</code></pre></td><td><strong><code>String</code></strong></td><td><p>Must have existing <strong><code>Sales Location</code></strong> in the accounting system.</p><p></p><p>E.g.: <code>HQ</code></p></td></tr><tr><td>Date</td><td><pre><code>docDate
</code></pre></td><td><strong><code>Date</code></strong></td><td>E.g.: <code>2024-08-12T00:00:00+08:00</code></td></tr><tr><td>Credit Term</td><td><pre><code>creditTerm
</code></pre></td><td><strong><code>String</code></strong></td><td><p><strong><code>Credit Term</code></strong> must match the same in the accounting system.</p><p></p><p>E.g.: <code>C.O.D.</code></p></td></tr><tr><td>Agent</td><td><pre><code>agent
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>JANE SMITH</code></td></tr><tr><td>Ref</td><td><pre><code>ref
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>REF-123456</code></td></tr><tr><td>Remark 2</td><td><pre><code>Remark2
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>PENDING</code></td></tr><tr><td>Multi Pricing</td><td><pre><code>multiPricing
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>Price 1</code></td></tr><tr><td>Description</td><td><pre><code>description
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>ORDER DESCRIPTION</code></td></tr><tr><td>Expiry Date</td><td><pre><code>SalesExemptionExpiryDate
</code></pre></td><td><strong><code>Date</code></strong></td><td>E.g.: <code>2024-10-17T00:00:00+08:00</code></td></tr><tr><td>Phone</td><td><pre><code>phone1
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>+1234567890</code></td></tr><tr><td>Fax</td><td><pre><code>fax1
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>+0987654321</code></td></tr><tr><td>Inclusive</td><td><pre><code>inclusiveTax
</code></pre></td><td><strong><code>Boolean</code></strong></td><td>E.g.: <code>true</code></td></tr><tr><td>Credit Term</td><td><pre><code>displayTerm
</code></pre></td><td><strong><code>String</code></strong></td><td><p><strong><code>Credit Term</code></strong> must match the same in the accounting system.</p><p></p><p>E.g.: <code>C.O.D.</code></p></td></tr><tr><td>UDF</td><td><pre><code>udf
</code></pre></td><td><strong><code>Object</code></strong></td><td><a href="#sales-orders-udf">Refer Below</a></td></tr><tr><td>Table Item</td><td><pre><code>details
</code></pre></td><td><strong><code>Array</code></strong></td><td><a href="#sales-orders-table-item">Refer Below</a></td></tr></tbody></table>

## Sales Order's UDF

<table><thead><tr><th>UI Name</th><th>Database</th><th>Type</th><th>Remarks</th></tr></thead><tbody><tr><td>Venue</td><td><pre><code>VENUE
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>CONFERENCE CENTER</code></td></tr><tr><td>Gmail</td><td><pre><code>Gmail
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>example@gmail.com</code></td></tr><tr><td>IC</td><td><pre><code>IC
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>S1234567D</code></td></tr><tr><td>Balance</td><td><pre><code>BALANCE
</code></pre></td><td><strong><code>Number</code></strong></td><td>E.g.: <code>1000</code></td></tr><tr><td>Payment</td><td><pre><code>PAYEMENT
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>CREDIT CARD</code></td></tr><tr><td>Branding</td><td><pre><code>BRANDING
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>BRAND X</code></td></tr><tr><td>Note</td><td><pre><code>Note
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>SPECIAL INSTRUCTIONS</code></td></tr><tr><td>PDate</td><td><pre><code>PDate
</code></pre></td><td><strong><code>Date</code></strong></td><td>E.g.: <code>2024-10-05T00:00:00+08:00</code></td></tr></tbody></table>

## Sales Order's Table Item

<table><thead><tr><th>UI Name</th><th>Database</th><th>Type</th><th>Remarks</th></tr></thead><tbody><tr><td>Item No</td><td><pre><code>ItemCode
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>ITEM-123456</code></td></tr><tr><td>Description</td><td><pre><code>description
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>ITEM DESCRIPTION</code></td></tr><tr><td>Description 2</td><td><pre><code>desc2
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>ADDITIONAL INFO</code></td></tr><tr><td>Delivery Date</td><td><pre><code>deliveryDate
</code></pre></td><td><strong><code>Date</code></strong></td><td>E.g.: <code>2024-10-17T00:00:00+08:00</code></td></tr><tr><td>Location</td><td><pre><code>location
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>WAREHOUSE 1</code></td></tr><tr><td>Quantity</td><td><pre><code>qty
</code></pre></td><td><strong><code>Number</code></strong></td><td><p>Value must be <strong>number</strong>, and value <strong>cannot</strong> be <strong>negative.</strong></p><p></p><p>E.g.: <code>10</code></p></td></tr><tr><td>UOM</td><td><pre><code>uom
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>PCS</code></td></tr><tr><td>Unit Price</td><td><pre><code>unitPrice
</code></pre></td><td><strong><code>Number</code></strong></td><td><p>Value must be <strong>number</strong>, and value <strong>cannot</strong> be <strong>negative.</strong></p><p></p><p>E.g.: <code>100</code></p></td></tr><tr><td>Subtotal</td><td><pre><code>subtotal
</code></pre></td><td><strong><code>Number</code></strong></td><td><p>Value must be <strong>number</strong>, and value <strong>cannot</strong> be <strong>negative.</strong></p><p></p><p>E.g.: <code>1000</code></p></td></tr><tr><td>Total</td><td><pre><code>total
</code></pre></td><td><strong><code>Number</code></strong></td><td><p>Value must be <strong>number</strong>, and value <strong>cannot</strong> be <strong>negative.</strong></p><p></p><p>E.g.: <code>1100</code></p></td></tr><tr><td>UDF</td><td><pre><code>udf
</code></pre></td><td><strong><code>Object</code></strong></td><td>E.g.: <code>"POSTTOPO": "T"</code></td></tr><tr><td>Description 2</td><td><pre><code>description2
</code></pre></td><td><strong><code>String</code></strong></td><td>E.g.: <code>ADDITIONAL DESCRIPTION</code></td></tr></tbody></table>

## Stock Transfer's Sample Code

{% hint style="warning" %}
Remember to change to the **correct field** before proceeding to run **ANY** script.
{% endhint %}

{% tabs %}
{% tab title="Logic Script" %}
{% hint style="info" %}
To find `{fieldName}`, you are required to have access to **Alpha** or use **Network** in Developer Tools `[F12]`.
{% endhint %}

{% code fullWidth="true" %}

```python
import clr

clr.AddReference("Newtonsoft.Json")
clr.AddReference("System.Net")
clr.AddReference("System.IO")

from System.Text import *
from Newtonsoft.Json import *
from Newtonsoft.Json.Linq import *
from System import *

clr.AddReference("System.Drawing")
from System.Drawing import Bitmap, Image
from System.Drawing.Imaging import ImageFormat
from System.IO import MemoryStream, StreamWriter
from System.Net import WebClient
import binascii
from System import BitConverter

# search
documentList = Module("{YOUR-MODULE-NAME}").findAll(
    {
        "$or": [
            {
                "Audit.UpdatedDate": {"$gt": Inputs["lastSync"]},
                "Audit.UpdatedBy": {"$ne": "External"},
                "Dynamic.Extension.{fieldName}": {"$in": [None, ""]},
            },
            {
                "Audit.UpdatedDate": {"$gt": Inputs["lastSync"]},
                "Dynamic.Extension.{fieldName}": True,
                "Dynamic.Extension.{fieldName}": {"$in": [None, ""]},
            },
        ]
    }
)
debug("documentList", documentList)

resultList = []

# added
def prepareRow(data, x):
    row = JObject()
    # row["ItemCode"] = x['Model']
    row["ItemCode"] = (
        str(x["{YOUR-ITEM-MODEL}"])[:30] if x["{YOUR-ITEM-ID}"] > 0 else None
    )
    row["description"] = x["{YOUR-ITEM-DESCRIPTION}"]
    row["desc2"] = (
        str(x["{YOUR-REMARKS}"])[:100] if x["{YOUR-REMARKS}"] is not None else None
    )
    row["deliveryDate"] = x["{YOUR-DELIVERY-DATE}"]
    row["location"] = data["{YOUR-WAREHOUSE-NAME}"]
    row["qty"] = x["{YOUR-QUANTITY}"]
    row["uom"] = x["{YOUR-ITEM-UOM}"] if x["{YOUR-ITEM-ID}"] > 0 else None
    row["unitPrice"] = x["{YOUR-UNIT-PRICE}"]
    row["subtotal"] = x["{YOUR-AMOUNT}"]
    row["total"] = x["{YOUR-AMOUNT}"]
    row["taxAdjustment"] = None
    row["udf"] = JObject()
    row["udf"]["POSTTOPO"] = x["{YOUR-POST-TO-PO}"]

    row["description2"] = x["{YOUR-REMARKS}"]

    if x["{YOUR-TAX-CODE-ID}"] > 0:
        row["taxType"] = x["{YOUR-TAX-CODE}"]["{YOUR-CODE}"]
        row["taxRate"] = x["{YOUR-TAX-CODE}"]["{YOUR-RATE}"].ToString()
    row["deliveryDate"] = x["{YOUR-DELIVERY-DATE}"]

    if (
        x["{YOUR-PHOTO}"] is not None
        and x["{YOUR-PHOTO}"]["{YOUR-PATH}"] is not None
        and x["{YOUR-PATH}"] != ""
    ):
        url = FilePathTranslator.GetPath(str(x["{YOUR-PHOTO}"]["{YOUR-PATH}"]))
        # debug('path', url)
        result = image_to_hex(url)
        # debug('pic', result)
        row["furtherDescription"] = result
    return row


def preparePayload(data):
    payloadData = JObject()
    payloadData["type"] = "SalesOrder"
    payloadData["cancelled"] = False
    payloadData["payload"] = JObject()
    payloadData["payload"]["docNo"] = data["{YOUR-DOCUMENT-ID}"]
    if data["{YOUR-CODE}"] != None and data["{YOUR-CODE}"] != 0:
        payloadData["payload"]["docKey"] = data["{YOUR-CODE}"]
    payloadData["payload"]["debtorCode"] = data["{YOUR-DEBTOR-CODE}"]
    payloadData["payload"]["debtorName"] = data["{YOUR-NAME}"]

    if data["{YOUR-ADDRESS}"] is not None:
        lines = data["{YOUR-ADDRESS}"].split("\n")
        for i, line in enumerate(lines):
            if i < 4:
                line = str(line.rstrip("\r"))[:40] if line is not None else ""
                payloadData["payload"]["invAddr{0}".format(i + 1)] = line
                payloadData["payload"]["DeliverAddr{0}".format(i + 1)] = line

    payloadData["payload"]["salesLocation"] = data["{YOUR-WAREHOUSE-NAME}"]
    # payloadData["payload"]["docNo"] = None if data['{YOUR-DOCUMENT-ID}'] == "" or data['{YOUR-DOCUMENT-ID}'] is None else data['{YOUR-DOCUMENT-ID}']
    payloadData["payload"]["docDate"] = data["{YOUR-ORDER-DATE}"]
    payloadData["payload"]["creditTerm"] = data["{YOUR-CREDIT-TERM}"]
    payloadData["payload"]["agent"] = data["{YOUR-SALESPERSON-CODE}"]
    payloadData["payload"]["ref"] = data["{YOUR-REFERENCE}"]
    payloadData["payload"]["Remark2"] = data["{YOUR-STATUS-2}"]

    payloadData["payload"]["udf"] = JObject()
    payloadData["payload"]["udf"]["VENUE"] = data["{YOUR-VENUE-NAME}"]
    payloadData["payload"]["udf"]["Gmail"] = data["{YOUR-EMAIL}"]
    payloadData["payload"]["udf"]["IC"] = data["{YOUR-IC-NO}"]
    payloadData["payload"]["udf"]["BALANCE"] = data["{YOUR-BALANCE}"]
    payloadData["payload"]["udf"]["PAYEMENT"] = (
        str(data["{YOUR-DEPOSIT-REFERENCE-NO}"])[:50]
        if data["{YOUR-DEPOSIT-REFERENCE-NO}"] is not None
        else None
    )

    payloadData["payload"]["udf"]["BRANDING"] = data["{YOUR-BRANDING}"]
    if data["{YOUR-BRANDING}"] is None or data["{YOUR-BRANDING}"] == "":
        payloadData["payload"]["udf"]["BRANDING"] = "NONE"

    payloadData["payload"]["udf"]["Note"] = (
        str(data["{YOUR-REMARKS}"])[:200]
        if data["{YOUR-REMARKS}"] is not None
        else None
    )
    payloadData["payload"]["udf"]["PDate"] = data["{YOUR-PROCESSING-DATE}"]

    if data["{YOUR-DELIVERY-DATE}"] is not None:
        payloadData["payload"]["SalesExemptionExpiryDate"] = data[
            "{YOUR-DELIVERY-DATE}"
        ]

    payloadData["payload"]["multiPricing"] = "{YOUR-MULTI-PRICING}"
    payloadData["payload"]["description"] = "{YOUR-DESCRIPTION}"
    payloadData["payload"]["phone1"] = data["{YOUR-CONTACT-NO}"]
    payloadData["payload"]["fax1"] = data["{YOUR-CONTACT-NO-2}"]

    # payloadData["payload"]["currencyRate"] = data['Exchange Rate'] // not use
    payloadData["payload"]["inclusiveTax"] = True
    payloadData["payload"]["displayTerm"] = data["{YOUR-CREDIT-TERM}"]
    payloadData["payload"]["details"] = JArray.FromObject(
        data["{YOUR-ITEMS}"].Select(lambda x: prepareRow(data, x))
    )
    payloadData["LastModified"] = data["{YOUR-UPDATED-DATE}"]
    return payloadData


# payload = JObject.FromObject(payloadData)
# data['Code'] = result['docKey']
# data['Sales Order No'] = result['docNo']

# end of added
for entry in documentList:
    payloadData = preparePayload(entry)
    resultList.append(payloadData)
    # debug('payloadData', payloadData)

debug("done", resultList)

# debug('resultList','done')
# test = JArray.FromObject(resultList)
# debug('here', 'here4')
outputs["results"] = JArray.FromObject(resultList)
# debug('result', resultList)
```

{% endcode %}
{% endtab %}
{% endtabs %}

**SQL ACCOUNTING integration - sales order**

<table><thead><tr><th width="498">example script</th><th>purpose</th></tr></thead><tbody><tr><td><p></p><pre><code>payloadData["type"] = "SL_SO"
</code></pre></td><td>to let the system know you integration with Sales Order</td></tr><tr><td><pre><code>payloadData["payload"]["DOCNO"] = data["SO Number"]
</code></pre></td><td>change ["DOCNO"]. You can refer below table</td></tr></tbody></table>

<table><thead><tr><th width="223">UI</th><th>mapping field</th><th width="187">type</th><th>remarks</th></tr></thead><tbody><tr><td>Customer</td><td>CODE</td><td>text</td><td>map to customer (need to make sure the customer code exist in SQL)</td></tr><tr><td>Fax (Delivery part)</td><td>DFAX1</td><td>text</td><td></td></tr><tr><td>Attention (Delivery part)</td><td>DATTENTION</td><td>text</td><td></td></tr><tr><td>Terms</td><td>TERMS</td><td>text</td><td>map to payment term (need to make sure the payment term code exist in SQL)</td></tr><tr><td>Description</td><td>DESCRIPTION</td><td>text</td><td></td></tr><tr><td>Ref 1</td><td>DOCREF1</td><td>text</td><td></td></tr><tr><td>S/O No</td><td>DOCNO</td><td>text</td><td></td></tr><tr><td>Date</td><td>DOCDATE</td><td>date</td><td></td></tr><tr><td>Ext. No</td><td>DOCNOEX</td><td>text</td><td></td></tr></tbody></table>

**SQL ACCOUNTING integration - sales order line**

<table><thead><tr><th width="571">example script</th><th>purpose</th></tr></thead><tbody><tr><td><pre><code>payloadData["payload"]["cdsDocDetail"] = JArray.FromObject(data['Details'].Select(lambda x: prepareRow(x)))
</code></pre></td><td>["cdsDocDetail"] mean map to line</td></tr></tbody></table>

| UI               | mapping field | type   |
| ---------------- | ------------- | ------ |
| More Description | DESCRIPTION3  | text   |
| Remark 1         | REMARK1       | text   |
| UOM              | UOM           | text   |
| U/Price          | UNITPRICE     | number |
| Qty              | QTY           | number |
| Disc             | DISC          | number |
