Package Description
# PraisovedSync **Client for the Praisoved service — keeps miniShop3 prices, stock and product attributes in step with an external price-list catalogue.** --- ## What it is PraisovedSync is the site-side client for [praisoved.com](https://praisoved.com/), a service that collects supplier price lists, merges them into one catalogue and works out what each product should cost. The shop keeps its catalogue where it belongs — in miniShop3. This package is the half that lives on the site: it hands the shop catalogue over to the service, and brings the resulting prices back. Nothing else about the shop changes. The package is useless on its own — an account on the service is required. ## How the exchange works **The site always starts the conversation.** The service never calls in. There is no webhook, no open endpoint, no public entry point of any kind; the front end of the site gains nothing that can be reached from outside. Two directions, both initiated by the site: | Direction | What happens | |---|---| | **In** | The site downloads an NDJSON exchange file from its personal link and applies prices, stock and attributes to matching products. | | **Out** | The site builds a CSV of its own catalogue and posts it to the service, so the service knows what the shop actually sells. | Products are matched by **resource id first, article number as a checksum**. The id is an address the service learned from the shop's own export; the article is there to catch the case where the catalogue changed underneath and the id now points at a different product. When the two disagree, the product is left alone and counted separately. For rows that carry no id — a catalogue uploaded to the service by hand, for instance — the article number, MPN or barcode column is used instead, and duplicate values are skipped rather than guessed at. ## What it writes Only what the exchange file is allowed to bring: - **Price**, when it differs by more than half a kopeck. - **Old price** — and only together with a price change, so the shop never shows a discount that does not exist. - **Stock**. - **Extra fields** of the product (miniShop3 extra fields). - **Options** (product attributes), converted to the option's own type: numbers, yes/no, dates, values from a fixed list. Multi-value options are written as a set. - **Weight** and **country of origin** — the only two base columns that are ever written back. - **Unpublish**, and only if the exchange file explicitly asks for that policy for products the service's catalogue no longer contains. Writing goes through **miniShop3's own product Update processor**, not straight into the tables, so plugins from other components still fire on `OnBeforeDocFormSave` / `OnDocFormSave`. Options are written through miniShop3's own option service. Resource locks are cleared before and after every run. ## What it never touches - **Never creates products.** Never deletes them. - **Never writes** the title, long title, menu title, description, images, article number, alias, category or vendor. - **Never creates** options, extra fields, categories or vendors that the site does not already have. - **Never touches** orders, customers, discounts, warehouses. - Products in the recycle bin are ignored; products with a duplicated match value are left alone entirely. ## What it sends out A CSV of the shop catalogue: site product id, article, title, category, vendor, country, price, old price, stock, weight, product URL, up to five image URLs — plus a column for every active extra field and every option that at least one product uses. Alongside the file go two dictionaries: the unit of measurement for each column, and the allowed values of multi-value options. Boolean options travel as words rather than as 1 and 0. Multi-value options are sorted, so the same catalogue always produces the same file. ## Safety The exchange is meant to be dull and reversible-by-hand, not clever: - **Preview mode is on out of the box.** The component reports what it would change and writes nothing until that switch is turned off. The "Synchronise" button refuses to bypass it and says which setting is in the way. - **Two passes over the file.** The first pass works out the plan and records it; only then are the limits checked and the second pass writes. - **A truncated download changes nothing.** The exchange file ends with an explicit end marker; without it the whole run is refused. A half-downloaded file is otherwise perfectly valid NDJSON, just shorter — and would have looked like "every product is out of stock". - **A price-change threshold** stops the run when the file would move prices further than allowed. The threshold is set on the service side, next to the catalogue it describes. - **The link must be https.** The certificate is verified. Verification can be switched off for local development, and the admin page says so in red for as long as it stays off. - One product failing to save does not abort the run — its id and the reason land in the run's notes. There is **no one-click rollback**. The journal keeps the previous value next to the new one for every field it changed, so a mistake can be undone by hand, but nothing in the component will undo it for you. ## Admin page A single page under the MODX manager, built on UIkit and htmx rather than ExtJS: - **Exchange** — a status block that says what is missing (no link, no miniShop3, preview mode still on, cron disabled), buttons for *Preview*, *Synchronise* and *Send catalogue*, and the run journal with a per-run "what changed" table showing old value beside new. - **How it works** — the manual, in place: what the component does, how to set it up, where the limits are, and a ready-to-paste cron line with the real path to this installation. Three permissions are supplied: `praisovedsync_view`, `praisovedsync_save`, `praisovedsync_remove`, with a policy and policy template to match. ## Scheduled runs A CLI script, run from the system cron: ``` 0 * * * * /usr/bin/php /path/to/site/core/components/praisovedsync/cron/sync.php --quiet ``` It refuses to run outside CLI and takes a file lock, so two overlapping cron runs cannot fight over the same catalogue. After a successful price run it also sends the catalogue up, if enough hours have passed since the last one. `--targets` prints a diagnostic list: every name under which this site will accept a value, with its type, and the image thumbnail sizes available. ## Requirements - **MODX Revolution 3.0** or newer. - **miniShop3.** - **PHP 8.2** or newer. - **MySQL / MariaDB.** - An account on [praisoved.com](https://praisoved.com/) — the package has nothing to talk to without one. ## Setup 1. Install the package. 2. Paste the personal exchange link from the service into `praisovedsync.feed_url`. 3. Point `praisovedsync.column_sku` at the column holding your article numbers (`article` by default), and check the result with *Preview*. 4. When the preview looks right, turn `praisovedsync.dry_run` off, turn `praisovedsync.enabled` on and add the cron line. Twenty system settings in four groups cover the rest: which columns identify a product, which title field to export, whether to send attributes and options, thumbnail size, network timeout, journal depth, and which user the product updates run as.
Details
- Developer(s)
- MisterWooster
- Released
- 2026-08-20
- First seen
- 2026-08-20
- License
- GPLv2
- Supported databases
- Minimum MODX Requirement
- 3.1
PraisovedSync Releases
| Vendor | Signature | Released on |
|---|---|---|
| MODX.com | 3.0.36-pl | 2026-08-20 (1 hour ago) |