ExampleUpdated 17 Oct 2026
Syncing data service
A scheduled service that fetches products from an external API and updates price and campaign fields on the matching documents in the site. SyncUrl and SyncToken are read from #/Config. Place the file at #/Services/SyncService.js and register it in #/Services.json, for example { "Schedules": [{ "Name": "Product sync", "Daily": ["06:00"], "Task": { "Path": "SyncService.js" } }] } - see Services - scheduling and events.
Example
Code #/Services/SyncService.js
export default () => {
let config = docly.getJson("#/Config") || {};
if (!config.SyncToken) throw new Error("SyncToken is not set in #/Config.");
if (!config.SyncUrl) throw new Error("SyncUrl is not set in #/Config.");
// httpPost does not throw when the call fails - it returns { DoclyError }.
let result = docly.httpPost(config.SyncUrl, { "token": config.SyncToken });
if (!result || result.DoclyError) throw new Error("Sync request failed: " + (result ? result.DoclyError : "no response"));
if (!Array.isArray(result)) throw new Error("Sync response is not a list.");
let products = docly.getFiles("/", { name: "*", recursive: true }) || [];
let errors = [];
let updates = [];
let notModified = [];
let n = new Date();
let now = docly.format(n, "yyyy-MM-dd") + "T" + docly.format(n, "HH:mm");
for (let p of result) {
let values = p.Values || {};
let sourceId = values.ROWID;
let target = products.find(x => x.ProductId == sourceId);
if (target == null) {
errors.push({ id: sourceId, name: p.Name, message: "Product not found" });
continue;
}
let newPrice = values.BasePrice;
let campaignPrice = "";
let campaignEnd = "";
// Is a campaign running on the product right now?
for (let c of values.Campaigns || []) {
if (c.FromDate <= now && c.ToDate >= now) {
campaignPrice = c.CampaignPrice;
campaignEnd = c.ToDate;
}
}
if (newPrice != target.Price || campaignPrice != target.CampaignPrice || campaignEnd != target.CampaignEnd) {
updates.push({
id: sourceId,
name: p.Name,
newPrice: newPrice,
oldPrice: target.Price,
campaignPrice: campaignPrice,
oldCampaignPrice: target.CampaignPrice,
campaignEnd: campaignEnd,
oldCampaignEnd: target.CampaignEnd
});
let targetPath = (target.folderpath || "") + "/" + target.filename;
docly.patchFile(targetPath, { "Price": newPrice, "CampaignPrice": campaignPrice, "CampaignEnd": campaignEnd });
} else {
notModified.push({ id: sourceId, name: p.Name });
}
}
return { products: result.length, updates: updates, notModified: notModified, errors: errors };
};