Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
moneyworks:billig_shipping_script [2026/02/18 17:13] Martin Falconermoneyworks:billig_shipping_script [2026/02/18 18:59] (current) Martin Falconer
Line 2: Line 2:
  
  
-The Billig shipping script, named 'Export_Billig' in the Airtox File, is for sending shipping orders to Billig (BA) for processing. +The Billig shipping script, named 'Export_Billig' in the Airtox File, is for sending shipping orders to Billig (BA) for processing.\\ 
-It runs as a MW script and uses CURL to send shipping orders over tcp/http. It is triggered by selecting Sales Invoices and pressing the "Export Billig" button.+It runs as a MW script and uses CURL to send shipping orders over tcp/http. It is triggered by selecting Sales Invoices and pressing the "Export Billig" button.\\ 
  
 ====== Technical documentation ====== ====== Technical documentation ======
Line 14: Line 15:
   * **Validates Delivery Addresses:** Checks the delivery address meets criteria.  More info below   * **Validates Delivery Addresses:** Checks the delivery address meets criteria.  More info below
   * **Validates Country 2 Char representation:** Billig API uses 2 Char country digits for addresses.  Uses JSON file to verify.   * **Validates Country 2 Char representation:** Billig API uses 2 Char country digits for addresses.  Uses JSON file to verify.
 +
 +===== Missing features: =====
 +
 +  * Unable to resend if send failure.  (MW script is probably not the place to do this. It is busy enough as it is)
 +  * No local record of sent orders (with MW SQLite, this could be done.  Again, script is pretty busy already)
 +  * If when adding a Sales Line to Sales Header fails.... no resend available as per above. Just gets left off order (has only happened a few times)
 +  * UI feedback while working. Bit of a limitation of long running MW script. (Only recommend sending max of 10 Sales Invoices)
  
 ===== BILLIG API Information: ===== ===== BILLIG API Information: =====
  
-**API is locked down by IPs.** The available IPs are Martin's Office IP, Airtox's Server IP+**API is locked down by IPs.** The available IPs are Martin's Office IP, Airtox's Server IP, and possibly TMF and/or Sussol IPs.\\ 
 +API looks like it is maintained by prentow.com (Contacts not added here as public page)
  
 ==== Test Site Enpoints ==== ==== Test Site Enpoints ====
Line 46: Line 55:
   * A Sales Header is created using the Sales Header endpoint   * A Sales Header is created using the Sales Header endpoint
   * Individual lines are added to Sales Header using the Lines Header endpoint   * Individual lines are added to Sales Header using the Lines Header endpoint
 +
 +
 +=== Sales Header Fields (text from script) ===
 +
 +Document_No = "AI" + transaction.OurRef\\
 +External_Docuement_No = "Inv-" + Transaction.OurRef + "/Ord-" + Transaction.TheirRef\\
 +shippingCodeLines = See below how shippingCodeLines are calculated\\
 +
 +  let pdata = "{\n  "
 +  let pdata = pdata + "\"Document_Type\": \"Ordre\",\n  "
 +  let pdata = pdata + "\"Document_No\": \"" + docNumber + "\",\n  "
 +  let pdata = pdata + "\"Customer_No\": \"" + billigCompanyNoPROP + "\",\n  "
 +  let pdata = pdata + "\"Shipment_Date\": \"" + shipDate + "\",\n  "
 +  let pdata = pdata + "\"Ship_to_Name\": \"" + shipToName + "\",\n  "
 +  let pdata = pdata + "\"Ship_to_Address\": \"" + addr1 + "\",\n  "
 +  let pdata = pdata + "\"Ship_to_Address_2\" : \"" + addr2 + "\",\n  "
 +  let pdata = pdata + "\"Ship_to_City\": \"" + shipToCity + "\",\n  "
 +  let pdata = pdata + "\"Ship_to_Post_Code\": \"" + shipToPostcode + "\",\n  "
 +  let pdata = pdata + "\"Ship_to_Country_Region_Code\": \"" + shipToCountry + "\",\n  "
 +  let pdata = pdata + shippingCodeLines
 +  let pdata = pdata + "\"External_Document_No\": \""+ extDocNumber +"\""
 +  let pdata = pdata + "\n}
 +  
 +=== Sales Line Fields (text from script) ===
 +
 +Document_No = "AI" + transaction.OurRef\\
 +Line_No = sequential integer number. 1, 2, 3, etc...\\
 +
 +  let pdata = "{\n  "
 +  let pdata = pdata + "\"Document_Type\": \"Ordre\",\n  "
 +  let pdata = pdata + "\"Document_No\": \"" + docNumber + "\",\n"
 +  let pdata = pdata + "\"Line_No\": \"" + lineNum  + "\",\n"
 +  let pdata = pdata + "\"Type\": \"Vare\",\n"
 +  let pdata = pdata + "\"Item_No\": \"" + itemCode + "\",\n"
 +  let pdata = pdata + "\"Quantity\" : "  + quantity 
 +  let pdata = pdata + "\n}"
 +  
 +=== Shipping Code Lines ===
 +
 +A few shipping codes are sent in the Sales Header.  It consists of 2 fields.
 +  * "Shipping_Agent_Code" : "predetermined shipping code created by Billig"
 +  * "Shipping_Agent_Service_Code" : "predetermined shipping service code created by Billig
 +
 +The logic depends (as of today, 17th Feb 2026):
 +
 +  * If internal order is for customer "BILLIG" These are interal orders sent to Billig warehouse.
 +    * "Shipping_Agent_Code" = "AFHENT_AIR"
 +    * "Shipping_Agent_Service_Code" = "AFHENT_AIR"
 +  * If destination country "DK" (Denmark)
 +    * "Shipping_Agent_Code" = "GLS"
 +    * "Shipping_Agent_Service_Code" = "GLS-ERH"
 +  * If destination country "FO", or "GL", or "IS"
 +    * "Shipping_Agent_Code" = "UPS-AIRTOX"
 +    * "Shipping_Agent_Service_Code" = "UPS_Saver"
 +  * If destination country is none of the above, and not "DK"
 +    * "Shipping_Agent_Code" = "UPS-AIRTOX"
 +    * "Shipping_Agent_Service_Code" = "UPS-AIRTOX"
  
 ==== Entry point: ==== ==== Entry point: ====
Line 66: Line 132:
       * If only 4 lines, third line must have City and Postcode on same line, in that order       * If only 4 lines, third line must have City and Postcode on same line, in that order
       * First line is always the Recipient Name       * First line is always the Recipient Name
-      * Last line is always the counrty name, or country 2 code letters, nothing more.  i.e "Denmark" or "DK", "Denmark 8444" would fail.+      * Last line is always the country name, or country 2 code letters, nothing more.  i.e "Denmark" or "DK", "Denmark 8444" would fail.
       * Second to last line must always be JUST postocde, or have postcode as last value on line.  i.e "Coppenhagen 8000"       * Second to last line must always be JUST postocde, or have postcode as last value on line.  i.e "Coppenhagen 8000"
       * Parse for 2 Char country code if full country name is given       * Parse for 2 Char country code if full country name is given
Line 72: Line 138:
     * Check order doesn't already exist with Billig     * Check order doesn't already exist with Billig
     * Create Sales Header     * Create Sales Header
-    * Add lines to Sales Header+    * Add lines to Sales Header, one by one