package com.example.slflo import java.util.UUID /** * The ERP's master data pushed to Slflo by its own keys, in the order references need: * units, the price list, items with their units and prices, customers. Every call is a PUT on * the ERP key, so a lost answer is retried as the same call. */ class MasterDataPushJob(private val api: SlfloClient, private val erp: ErpBooks) { /** What each push answered, by its path: `created`, `updated`, `unchanged` or `stale`. */ fun run(units: List, priceList: String, currency: String = "EGP"): Map { // One key per call per run: a retry inside the run replays, the next run gets real answers. val run = UUID.randomUUID().toString().take(RUN_ID_LENGTH) val results = linkedMapOf() fun put(path: String, body: Any) { results[path] = api.put(path, body, "md:$run:$path").path("data").path("result").asText() } units.forEach { put("/units/$it", mapOf("name" to mapOf("en" to it))) } put("/price-lists/$priceList", mapOf("currency" to currency, "name" to mapOf("en" to priceList))) erp.items().forEach { item -> put("/products/${item.number}", mapOf("name" to mapOf("en" to item.name), "base_unit_ref" to item.unit, "active" to true)) put("/products/${item.number}/units", mapOf("units" to listOf(mapOf("unit_ref" to item.unit, "factor_to_base" to 1, "order_default" to true)))) } val prices = erp.items().map { mapOf("product_ref" to it.number, "unit_ref" to it.unit, "price" to it.price, "valid_from" to "2026-01-01") } prices.chunked(MAX_ROWS).forEachIndexed { n, chunk -> val answer = api.put("/price-lists/$priceList/prices", mapOf("prices" to chunk), "md:$run:prices:$n", query = mapOf("mode" to "merge")).path("data") results["/price-lists/$priceList/prices#$n"] = if (answer.path("written").asInt() == 0) "unchanged" else "updated" } erp.customers().forEach { customer -> put( "/customers/${customer.account}", mapOf("name" to mapOf("en" to customer.name), "blocked" to false, "credit_limit" to customer.creditLimit, "price_list_ref" to customer.priceList), ) } return results } private companion object { const val MAX_ROWS = 500 const val RUN_ID_LENGTH = 12 } }