=== Cost & Margin Pricing for WooCommerce ===
Contributors: pihlfelt
Tags: cost of goods, purchase price, margin, pricing, supplier
Requires at least: 6.5
Tested up to: 7.0
Requires PHP: 8.1
Stable tag: 1.0.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Calculate sale prices from purchase prices: margin rules, supplier price list import, multi-currency costs and price rounding.

== Description ==

Set your margin once. Import your supplier's price list. Get finished, well-rounded prices.

Cost & Margin Pricing calculates sale prices from your purchase prices — with support for purchase prices in foreign currencies, daily exchange rates, margin or markup rules, psychological price rounding and a recurring supplier price list import with a full change preview.

Built on WooCommerce core fields: the selected purchase cost is always written back to WooCommerce's own Cost of Goods Sold (COGS) field, so Woo's reports, exports and every third-party COGS integration keep working. No parallel cost fields, ever.

**Safe by design**

* Nothing is ever applied without a preview — you always see the change diff first
* Every run is journaled and can be undone with one click
* Manually adjusted prices are detected and never silently overwritten
* Locked products are always skipped

**EU Omnibus ready**

Marketing a price cut in the EU requires showing the product's lowest price of the last 30 days — data WooCommerce does not keep. This plugin does: every price change is logged (including ones made outside the plugin), and each product's 30-day lowest price is computed for you. Show it to customers with the `[pihlcmp_lowest_price]` shortcode — a discreet, theme-friendly line like "Lowest price last 30 days: 199 kr" with CSS classes for styling, and a `label` attribute to change or remove the text. Nothing is ever added to your storefront unless you place it yourself.

**Free version**

* One supplier per product with purchase price in any major currency
* Daily exchange rates (ECB reference rates, with automatic fallback)
* One global margin/markup rule with price rounding
* CSV price list import/export with change preview
* Write-back to WooCommerce core COGS
* Change journal with one-click undo
* Price change log — also records price/cost edits made outside the plugin (who, when, what)
* Margin health warnings: products selling below real cost and sales priced below cost
* Lowest price last 30 days per product — the EU Omnibus reference for sale marketing
* Optional scheduled runs (monthly) — explicit opt-in, fully journaled and undoable

**Pro**

* Multiple suppliers per product with cost strategy (preferred/lowest/highest)
* Master list import: one file covering all suppliers, with a supplier column deciding each row
* Rules per category, supplier and product — plus per-product overrides on the product page
* Margin-based sale prices with flags, schedule dates and a management page
* Margin floor with warnings
* Scheduled runs at any interval: daily, weekly, biweekly or monthly (Free: monthly) — with an email report of every change after each run
* Reports: margins per product and category, low-margin lists, and a supplier comparison with potential savings
* Excel (.xlsx) import — upload the supplier's file directly

== External Services ==

This plugin fetches currency exchange rates from two services: on a daily schedule, when a new currency first needs a rate (e.g. during an import preview), and when you click "Fetch rates now" — and only when you use purchase prices in a currency other than your store currency.

**European Central Bank (ECB) reference rates** — the primary source. The plugin requests the public daily reference rate file. No personal data and no data about your store is sent; it is a plain file download. Terms: https://www.ecb.europa.eu/services/disclaimer/html/index.en.html

**ExchangeRate-API open endpoint (open.er-api.com)** — used as fallback when the ECB feed is unavailable, and for currencies the ECB does not publish. The request URL contains only your store's base currency code; no personal data and no other data about your store is sent. Terms: https://www.exchangerate-api.com/terms — attribution is shown on the plugin's settings page as required.

Rates are indicative reference rates intended for price calculation suggestions, not for payment processing.

== Frequently Asked Questions ==

= Does this replace WooCommerce's Cost of Goods field? =

No — it builds on it. The plugin stores supplier, currency and exchange rate details, and always writes the resulting cost to WooCommerce core's COGS field. Woo's own reports and exports keep working.

= Can prices be changed without my approval? =

Only if you explicitly enable scheduled automatic runs in Settings — and even then, changes above your confirmation threshold are never auto-applied, locked and manually re-priced products are never touched, and every run is journaled and undoable. With the feature off (the default), every rule run and import produces a preview diff that you apply explicitly. Products you have adjusted manually are detected and skipped until you actively release them.

= How do sale prices work? =

A product's sale price can come from two places, and you always win:

*You*: type a price in WooCommerce's normal sale price field (e.g. a weekend campaign at a fixed price). The plugin recognizes that this sale is yours and leaves the whole product alone until you remove it.

*The plugin* (Pro): rules decide WHAT sale margin applies (the "Sale price value" on a global, category, supplier or product rule — e.g. ordinary margin 40%, sale margin 20%), and a per-product on-sale flag decides WHICH products are on sale. Set the flag with the checkbox on the product's Cost & Margin tab, or in bulk via an on_sale column (yes/no) in the import file — sale_start/sale_end columns (YYYY-MM-DD) fill WooCommerce's normal schedule dates. Flagged products get a cost-following sale price on the next run — it is recalculated when costs change and removed automatically when you clear the flag. The Sales page lists every plugin-managed sale with one-click "End sale" buttons (and "End ALL"), journaled and undoable.

The plugin only ever manages sale prices it wrote itself. A manually set or hand-edited sale price is never touched, whatever flags or settings say.

= What do blank cells in the import file mean? =

Blank always means "leave unchanged" — a file can never accidentally clear something by omitting it. on_sale yes with no dates = on sale until you turn it off (a leftover, already-ended schedule from an old campaign is cleared automatically so "yes" means visibly on sale). To explicitly remove a schedule date, put a dash (-) in the date cell. The only required columns are a cost column and one identifier column.

= Does the plugin track price history? =

Yes. Every change the plugin makes is journaled, and price/cost edits made anywhere else (the product editor, other plugins, the REST API, scheduled sales) are logged too — visible under "Recent changes" on the product's Cost & Margin tab. This also gives you the lowest price of the last 30 days per product, the reference value the EU Omnibus rules require when marketing a price cut. The log starts at plugin activation; earlier history cannot be known.

= How do I show the 30-day lowest price to customers? =

Place the `[pihlcmp_lowest_price]` shortcode where you want it — in the product description, a block, or your theme's product template (`echo do_shortcode( '[pihlcmp_lowest_price]' );`). It renders a discreet line: "Lowest price last 30 days: 199 kr". Use `label="Your text:"` to change the text, `label=""` for the bare price, and `id="123"` outside a product context. The output carries the CSS classes `pihlcmp-lowest-price`, `pihlcmp-lowest-price-label` and `pihlcmp-lowest-price-value` so you can style every part; no styling is imposed. The plugin never adds anything to your storefront on its own.

= Which currencies are supported? =

All major currencies via the ECB daily reference rates (about 30), and roughly 130 more via the automatic fallback source. You can also enter exchange rates manually — manual rates always win.

== Screenshots ==

1. Price runs — preview every change before applying: old and new price, the resulting real margin, and exactly which parameters built each price. Large changes need a per-row tick; every applied run has one-click Undo.
2. Import, step 2 — the supplier's file with auto-detected separator and encoding; map the columns once and the mapping is remembered per supplier.
3. Import, step 3 — every row matched to your products with cost changes, calculated prices and the full calculation breakdown; large changes wait for your tick.
4. Pricing rules — set the margin or markup once, add landed costs, and land prices on psychological endings like …199.
5. Suppliers — currencies, FX buffers, lead times and minimum order values in one place.
6. Settings — the two safety thresholds, manual exchange rates, and current rates with their source.
7. Automatic runs — optional scheduled repricing (explicit opt-in) with the full safety net spelled out.

== Changelog ==

= 1.0.0 =
* Initial release.
