diff --git a/fusion_plating/docs/superpowers/plans/2026-05-29-configurable-charge-tax-lot-pricing-plan.md b/fusion_plating/docs/superpowers/plans/2026-05-29-configurable-charge-tax-lot-pricing-plan.md
new file mode 100644
index 00000000..d7dfdcfb
--- /dev/null
+++ b/fusion_plating/docs/superpowers/plans/2026-05-29-configurable-charge-tax-lot-pricing-plan.md
@@ -0,0 +1,559 @@
+# Configurable Charge + Order-Level Tax + Lot Pricing — Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** In Direct/Express order entry, replace the fixed "Tooling Charge" with a configurable/creatable charge type, add one order-level tax applied to (subtotal + charge), and add per-line lot pricing.
+
+**Architecture:** A small `fp.additional.charge.type` model feeds a searchable/quick-create dropdown. The wizard gains `charge_type_id` + `charge_amount` + a single `tax_id`; `_compute_totals` is simplified to one tax on (subtotal + charge). Lot pricing is a per-line `is_lot_priced` + `lot_total` whose onchange derives `unit_price`. On SO-create the one tax goes on every line + the charge line.
+
+**Tech Stack:** Odoo 19 (ORM, `@api.onchange`, `account.tax.compute_all`), QWeb form views, `TransactionCase`.
+
+**Spec:** [docs/superpowers/specs/2026-05-29-configurable-charge-tax-lot-pricing-design.md](../specs/2026-05-29-configurable-charge-tax-lot-pricing-design.md)
+
+**Conventions:**
+- Local runner (db `modsdev`): `docker exec odoo-modsdev-app odoo -d modsdev --test-enable --test-tags /fusion_plating_configurator -u fusion_plating_configurator --stop-after-init --http-port=0 --gevent-port=0 2>&1 | tail -60`. **Local Docker is down this session** — tests are written now and run on entech in the batched deploy. `python -m py_compile` + `xml.dom.minidom.parse` are the local sanity checks.
+- One `version` bump on `fusion_plating_configurator/__manifest__.py` (Task 1).
+
+---
+
+## Phase 1 — Charge type model + config UI
+
+### Task 1: `fp.additional.charge.type` model, ACL, views/menu, seed
+
+**Files:**
+- Create: `fusion_plating_configurator/models/fp_additional_charge_type.py`
+- Create: `fusion_plating_configurator/views/fp_additional_charge_type_views.xml`
+- Create: `fusion_plating_configurator/data/fp_additional_charge_type_data.xml`
+- Create: `fusion_plating_configurator/tests/test_charge_tax_lot.py`
+- Modify: `fusion_plating_configurator/models/__init__.py`
+- Modify: `fusion_plating_configurator/tests/__init__.py`
+- Modify: `fusion_plating_configurator/security/ir.model.access.csv`
+- Modify: `fusion_plating_configurator/__manifest__.py` (data list + version)
+
+- [ ] **Step 1: Write the failing test**
+
+Create `fusion_plating_configurator/tests/test_charge_tax_lot.py`:
+
+```python
+# -*- coding: utf-8 -*-
+# Copyright 2026 Nexa Systems Inc.
+# License OPL-1 (Odoo Proprietary License v1.0)
+"""Configurable charge + order-level tax + lot pricing (spec 2026-05-29)."""
+from odoo.tests.common import TransactionCase, tagged
+
+
+@tagged('post_install', '-at_install', 'fp_charge_tax_lot')
+class TestChargeTaxLot(TransactionCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.partner = cls.env['res.partner'].create({'name': 'ChargeCust'})
+ cls.tax13 = cls.env['account.tax'].create({
+ 'name': 'FP Test 13%',
+ 'amount': 13.0,
+ 'amount_type': 'percent',
+ 'type_tax_use': 'sale',
+ })
+
+ # ----- Task 1: charge type model -----
+ def test_charge_type_quick_create_and_default(self):
+ ct = self.env['fp.additional.charge.type'].create({
+ 'name': 'Rush Fee', 'default_amount': 75.0,
+ })
+ self.assertEqual(ct.name, 'Rush Fee')
+ self.assertEqual(ct.default_amount, 75.0)
+ # name_create (quick-create from the dropdown) works on a bare name
+ cid, cname = self.env['fp.additional.charge.type'].name_create('Setup')
+ self.assertTrue(cid)
+```
+
+Register in `fusion_plating_configurator/tests/__init__.py` — append:
+
+```python
+from . import test_charge_tax_lot
+```
+
+- [ ] **Step 2: Run → FAIL** (`KeyError: 'fp.additional.charge.type'`).
+
+```bash
+docker exec odoo-modsdev-app odoo -d modsdev --test-enable --test-tags /fusion_plating_configurator -u fusion_plating_configurator --stop-after-init --http-port=0 --gevent-port=0 2>&1 | tail -40
+```
+
+- [ ] **Step 3: Create the model**
+
+`fusion_plating_configurator/models/fp_additional_charge_type.py`:
+
+```python
+# -*- coding: utf-8 -*-
+# Copyright 2026 Nexa Systems Inc.
+# License OPL-1 (Odoo Proprietary License v1.0)
+# Part of the Fusion Plating product family.
+
+from odoo import fields, models
+
+
+class FpAdditionalChargeType(models.Model):
+ """A configurable, reusable 'additional charge' label (Tooling, Rush,
+ Setup, …) picked on the order-entry summary. Searchable + quick-create.
+
+ Spec: docs/superpowers/specs/2026-05-29-configurable-charge-tax-lot-pricing-design.md
+ """
+ _name = 'fp.additional.charge.type'
+ _description = 'Fusion Plating — Additional Charge Type'
+ _order = 'sequence, name'
+
+ name = fields.Char(string='Charge Type', required=True)
+ default_amount = fields.Monetary(
+ string='Default Amount', currency_field='currency_id',
+ help='Optional amount pre-filled when this type is picked on an '
+ 'order. The operator can override it.',
+ )
+ currency_id = fields.Many2one(
+ 'res.currency', default=lambda self: self.env.company.currency_id,
+ )
+ active = fields.Boolean(default=True)
+ sequence = fields.Integer(default=10)
+```
+
+Add to `fusion_plating_configurator/models/__init__.py` after `fp_part_description_version`:
+
+```python
+from . import fp_part_description_version
+from . import fp_additional_charge_type
+```
+
+Append 3 rows to `fusion_plating_configurator/security/ir.model.access.csv`:
+
+```csv
+access_fp_additional_charge_type_user,fp.additional.charge.type.user,model_fp_additional_charge_type,base.group_user,1,0,0,0
+access_fp_additional_charge_type_estimator,fp.additional.charge.type.estimator,model_fp_additional_charge_type,fusion_plating.group_fp_sales_rep,1,1,1,0
+access_fp_additional_charge_type_manager,fp.additional.charge.type.manager,model_fp_additional_charge_type,fusion_plating.group_fp_manager,1,1,1,1
+```
+
+- [ ] **Step 4: Views + menu + seed**
+
+`fusion_plating_configurator/views/fp_additional_charge_type_views.xml`:
+
+```xml
+
+
+
+ fp.additional.charge.type.list
+ fp.additional.charge.type
+
+
+
+
+
+
+
+
+
+
+
+
+ Additional Charge Types
+ fp.additional.charge.type
+ list
+
+
+
+
+```
+
+`fusion_plating_configurator/data/fp_additional_charge_type_data.xml`:
+
+```xml
+
+
+
+ Tooling Charge
+ 1
+
+
+```
+
+Register both in `fusion_plating_configurator/__manifest__.py` `data` list — add after `'views/fp_pricing_rule_views.xml',`:
+
+```python
+ 'views/fp_pricing_rule_views.xml',
+ 'views/fp_additional_charge_type_views.xml',
+```
+and after `'data/fp_sale_description_template_data.xml',`:
+
+```python
+ 'data/fp_sale_description_template_data.xml',
+ 'data/fp_additional_charge_type_data.xml',
+```
+
+Bump `version`: `19.0.22.8.0` → `19.0.23.0.0`.
+
+- [ ] **Step 5: Run → PASS** (same command). Then `python -m py_compile fusion_plating_configurator/models/fp_additional_charge_type.py` and `python -c "import xml.dom.minidom; [xml.dom.minidom.parse(f) for f in ['fusion_plating_configurator/views/fp_additional_charge_type_views.xml','fusion_plating_configurator/data/fp_additional_charge_type_data.xml']]; print('XML_OK')"`.
+
+- [ ] **Step 6: Commit**
+
+```bash
+git add fusion_plating_configurator/models/fp_additional_charge_type.py \
+ fusion_plating_configurator/models/__init__.py \
+ fusion_plating_configurator/views/fp_additional_charge_type_views.xml \
+ fusion_plating_configurator/data/fp_additional_charge_type_data.xml \
+ fusion_plating_configurator/security/ir.model.access.csv \
+ fusion_plating_configurator/tests/test_charge_tax_lot.py \
+ fusion_plating_configurator/tests/__init__.py \
+ fusion_plating_configurator/__manifest__.py
+git commit -m "feat(configurator): fp.additional.charge.type model + config menu + seed"
+```
+
+---
+
+## Phase 2 — Wizard charge + tax fields + recompute
+
+### Task 2: charge_type_id + charge_amount + tax_id on the wizard
+
+**Files:**
+- Modify: `fusion_plating_configurator/wizard/fp_direct_order_wizard.py` (fields ~`:312`, add onchange)
+
+- [ ] **Step 1: Add the fields + onchange.** After the `tooling_charge` field (keep it as a legacy column for in-flight drafts), add:
+
+```python
+ charge_type_id = fields.Many2one(
+ 'fp.additional.charge.type', string='Additional Charge',
+ )
+ charge_amount = fields.Monetary(
+ string='Charge Amount', currency_field='currency_id',
+ )
+ tax_id = fields.Many2one(
+ 'account.tax', string='Tax',
+ domain="[('type_tax_use', '=', 'sale')]",
+ default=lambda self: self.env.company.account_sale_tax_id,
+ help='One tax applied to (subtotal + additional charge). Every '
+ 'line + the charge line gets this tax on the created order.',
+ )
+
+ @api.onchange('charge_type_id')
+ def _onchange_charge_type_id(self):
+ for rec in self:
+ if rec.charge_type_id and not rec.charge_amount:
+ rec.charge_amount = rec.charge_type_id.default_amount
+```
+
+Confirm `api` is imported at the top of the file (it is — the wizard uses `@api.depends`).
+
+- [ ] **Step 2: py_compile + commit**
+
+```bash
+python -m py_compile fusion_plating_configurator/wizard/fp_direct_order_wizard.py
+git add fusion_plating_configurator/wizard/fp_direct_order_wizard.py
+git commit -m "feat(configurator): wizard charge_type_id + charge_amount + order-level tax_id"
+```
+
+### Task 3: `_compute_totals` — one tax on (subtotal + charge)
+
+**Files:**
+- Modify: `fusion_plating_configurator/wizard/fp_direct_order_wizard.py` (`_compute_totals` ~`:386-446`)
+
+- [ ] **Step 1: Write the failing test** — append to `TestChargeTaxLot`:
+
+```python
+ # ----- Task 3: totals -----
+ def _make_wizard(self, **kw):
+ vals = {'partner_id': self.partner.id}
+ vals.update(kw)
+ return self.env['fp.direct.order.wizard'].create(vals)
+
+ def test_tax_applies_on_subtotal_plus_charge(self):
+ wiz = self._make_wizard(charge_amount=100.0, tax_id=self.tax13.id)
+ self.env['fp.direct.order.line'].create({
+ 'wizard_id': wiz.id, 'quantity': 1, 'unit_price': 50.0,
+ })
+ wiz.invalidate_recordset()
+ # subtotal 50 + charge 100 = 150; 13% -> 19.50
+ self.assertEqual(wiz.total_subtotal, 50.0)
+ self.assertAlmostEqual(wiz.total_tax, 19.5, places=2)
+ self.assertAlmostEqual(wiz.total_amount, 169.5, places=2)
+```
+
+> If `fp.direct.order.wizard` create raises for a missing required field, set it in `_make_wizard` (read the model's `required=True` fields). `currency_id` typically defaults from the company.
+
+- [ ] **Step 2: Run → FAIL** (tax still computed per-line + tooling-after-tax → wrong numbers).
+
+- [ ] **Step 3: Replace the compute body.** Replace the per-line tax loop + tooling block (the body of `_compute_totals`, roughly `:404-445`) with:
+
+```python
+ for rec in self:
+ subtotal = sum(
+ (l.quantity or 0) * (l.unit_price or 0.0)
+ for l in rec.line_ids
+ )
+ charge = rec.charge_amount or rec.tooling_charge or 0.0
+ tax_total = 0.0
+ if rec.tax_id and (subtotal + charge):
+ res = rec.tax_id.compute_all(
+ subtotal + charge,
+ currency=rec.currency_id,
+ quantity=1,
+ product=None,
+ partner=rec.partner_id or None,
+ )
+ tax_total = res['total_included'] - res['total_excluded']
+ rec.total_subtotal = subtotal
+ rec.total_tax = tax_total
+ rec.total_amount = subtotal + charge + tax_total
+ rec.total_qty = sum(rec.line_ids.mapped('quantity'))
+ rec.total_line_count = len(rec.line_ids)
+```
+
+Update the `@api.depends` decorator above `_compute_totals` to:
+
+```python
+ @api.depends(
+ 'line_ids.quantity',
+ 'line_ids.unit_price',
+ 'charge_amount',
+ 'tooling_charge',
+ 'tax_id',
+ 'partner_id',
+ 'currency_id',
+ )
+```
+
+- [ ] **Step 4: Run → PASS.** py_compile.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add fusion_plating_configurator/wizard/fp_direct_order_wizard.py \
+ fusion_plating_configurator/tests/test_charge_tax_lot.py
+git commit -m "feat(configurator): totals = one tax on (subtotal + charge)"
+```
+
+---
+
+## Phase 3 — Lot pricing (per line)
+
+### Task 4: `is_lot_priced` + `lot_total` + onchange on the wizard line
+
+**Files:**
+- Modify: `fusion_plating_configurator/wizard/fp_direct_order_line.py` (fields ~`:235-240`)
+
+- [ ] **Step 1: Write the failing test** — append to `TestChargeTaxLot`:
+
+```python
+ # ----- Task 4: lot pricing -----
+ def test_lot_onchange_derives_unit_price(self):
+ wiz = self._make_wizard()
+ line = self.env['fp.direct.order.line'].new({
+ 'wizard_id': wiz.id, 'quantity': 500, 'lot_total': 1000.0,
+ 'is_lot_priced': True,
+ })
+ line._onchange_lot_pricing()
+ self.assertEqual(line.unit_price, 2.0)
+```
+
+- [ ] **Step 2: Run → FAIL** (`AttributeError: ... '_onchange_lot_pricing'`).
+
+- [ ] **Step 3: Add the fields + onchange** after `unit_price` (`:237-240`):
+
+```python
+ is_lot_priced = fields.Boolean(
+ string='Lot Price',
+ help='Price the whole quantity as a flat lot total instead of '
+ 'per unit. Unit price is derived = lot total / quantity; '
+ 'the quantity is preserved for production.',
+ )
+ lot_total = fields.Monetary(
+ string='Lot Total', currency_field='currency_id',
+ )
+
+ @api.onchange('is_lot_priced', 'lot_total', 'quantity')
+ def _onchange_lot_pricing(self):
+ for line in self:
+ if line.is_lot_priced and line.quantity:
+ line.unit_price = (line.lot_total or 0.0) / line.quantity
+```
+
+Confirm `api` is imported in `fp_direct_order_line.py` (it is — the file uses `@api.onchange` already).
+
+- [ ] **Step 4: Run → PASS.** py_compile.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add fusion_plating_configurator/wizard/fp_direct_order_line.py \
+ fusion_plating_configurator/tests/test_charge_tax_lot.py
+git commit -m "feat(configurator): per-line lot pricing (derive unit price, keep qty)"
+```
+
+---
+
+## Phase 4 — SO creation: order-level tax + typed charge line
+
+### Task 5: apply the one tax to every line + the charge line; name the charge by type
+
+**Files:**
+- Modify: `fusion_plating_configurator/wizard/fp_direct_order_wizard.py` (`action_create_order` part-line vals `:903-904`, tooling line `:913-929`)
+- Modify: `fusion_plating_configurator/models/sale_order_line.py` (SO-line ref fields)
+
+- [ ] **Step 1: SO-line ref fields.** In `sale_order_line.py`, add (near the other `x_fc_*` fields):
+
+```python
+ x_fc_is_lot_priced = fields.Boolean(string='Lot Priced')
+ x_fc_lot_total = fields.Monetary(
+ string='Lot Total', currency_field='currency_id')
+```
+
+- [ ] **Step 2: Part lines → order-level tax + lot stamp.** In `action_create_order`, change the part-line `tax_ids` (`:903-904`) and add the lot fields:
+
+```python
+ 'tax_ids': ([(6, 0, self.tax_id.ids)]
+ if self.tax_id else False),
+ 'x_fc_is_lot_priced': line.is_lot_priced,
+ 'x_fc_lot_total': line.lot_total or 0.0,
+ }))
+```
+
+- [ ] **Step 3: Charge line → typed + order-level tax.** Replace the tooling-line block (`:913-929`):
+
+```python
+ # Additional charge — one typed line, taxed by the order-level tax.
+ charge_amt = self.charge_amount or self.tooling_charge or 0.0
+ if charge_amt:
+ charge_name = (self.charge_type_id.name
+ if self.charge_type_id else _('Additional Charge'))
+ so_vals['order_line'].append((0, 0, {
+ 'product_id': product.id,
+ 'name': charge_name,
+ 'product_uom_qty': 1.0,
+ 'price_unit': charge_amt,
+ 'x_fc_internal_description': _(
+ 'Additional charge added via Express Orders.'
+ ),
+ 'tax_ids': ([(6, 0, self.tax_id.ids)]
+ if self.tax_id else False),
+ }))
+```
+
+Also, near the SO header vals (`:821` `x_fc_tooling_charge`), add the charge ref (leave `x_fc_tooling_charge` line in place):
+
+```python
+ 'x_fc_tooling_charge': self.charge_amount or self.tooling_charge or 0.0,
+```
+(SO header keeps a single amount field; the type is captured on the charge line's name. No new SO header field needed — keeps it minimal.)
+
+- [ ] **Step 4: py_compile + commit**
+
+```bash
+python -m py_compile fusion_plating_configurator/wizard/fp_direct_order_wizard.py \
+ fusion_plating_configurator/models/sale_order_line.py
+git add fusion_plating_configurator/wizard/fp_direct_order_wizard.py \
+ fusion_plating_configurator/models/sale_order_line.py
+git commit -m "feat(configurator): SO-create applies one tax to all lines + typed charge line"
+```
+
+Integration (full SO create + tax on every line) is verified on entech in Phase 6.
+
+---
+
+## Phase 5 — Express summary + line views
+
+### Task 6: reorder summary (charge type+amount, tax type+amount) + line lot toggle + remove per-line tax
+
+**Files:**
+- Modify: `fusion_plating_configurator/views/fp_express_order_views.xml` (line list `:288-316`, summary card `:343-385`)
+
+- [ ] **Step 1: Line list — add lot fields, remove per-line tax.** In the `line_ids` list, after the `unit_price` field block (`:289-293`) add the lot toggle + total, and make `unit_price` readonly when lot-priced; then DELETE the `tax_ids` block (`:310-315`):
+
+Replace the `unit_price` field block with:
+
+```xml
+
+
+
+```
+
+And remove the entire `` block (`:310-315`) — the order-level tax now governs.
+
+- [ ] **Step 2: Summary card — reorder + new fields.** Replace the three rows Tax (`:351-357`) and Tooling Charge (`:358-364`) so the order becomes Subtotal → **Additional Charge** → **Tax**:
+
+```xml
+
+
Additional Charge
+
+
+
+
+
+
+```
+
+(Subtotal row `:344-350` stays first; Total Lines/Total Quantity/Grand Total stay after.)
+
+- [ ] **Step 3: Validate XML**
+
+```bash
+python -c "import xml.dom.minidom; xml.dom.minidom.parse(r'fusion_plating_configurator/views/fp_express_order_views.xml'); print('XML_OK')"
+```
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add fusion_plating_configurator/views/fp_express_order_views.xml
+git commit -m "feat(configurator): express summary — charge type + tax type + lot column"
+```
+
+---
+
+## Phase 6 — Deploy + verify on entech (batched)
+
+- [ ] **Step 1: Run the suite** (entech during deploy, or modsdev when Docker's up):
+
+```bash
+docker exec odoo-modsdev-app odoo -d modsdev --test-enable --test-tags /fusion_plating_configurator -u fusion_plating_configurator --stop-after-init --http-port=0 --gevent-port=0 2>&1 | tail -60
+```
+Expected: `test_charge_tax_lot` passes + no regressions.
+
+- [ ] **Step 2: Manual walkthrough on entech** (hard-refresh the browser first — JS/SCSS bundle unaffected, but the form view changed):
+ 1. Open Express / Direct Order. The summary shows **Subtotal → Additional Charge (type dropdown + amount) → Tax (type dropdown + amount) → Total Lines → Total Quantity → Grand Total**.
+ 2. Pick a charge type (or type a new one → "Create"); confirm the amount pre-fills from its default; confirm Tax = tax_id × (subtotal + charge) and Grand Total updates.
+ 3. On a line, tick **Lot**, set qty 500 + Lot Total 1000 → unit price shows 2.00, line subtotal 1000, qty stays 500.
+ 4. Create the order → the charge appears as a line named by its type; every line + the charge line carry the chosen tax; the SO total matches the summary.
+
+---
+
+## Notes / deferred
+
+- Quote configurator, multiple charges, multiple taxes at once, per-charge-type product mapping, fiscal-position tax defaulting — out of scope (spec §7).
+- `tooling_charge` (wizard) + `x_fc_tooling_charge` (SO header) are kept as legacy columns; new flows use `charge_amount`. The compute + create both fall back to `tooling_charge` so in-flight saved drafts don't lose their value.
+- Lot rounding: `lot_total / quantity` is rounded to the price decimal precision; even divisions are exact, odd ones can differ by a cent or two on the line total (accepted per design D5).