Prechádzať zdrojové kódy

Add implementation analysis for per-order-item print status (v1.5.0)

Planning document for the proposed v1.5.0 feature — adding a per-line-item
print status (pending-print / in-print / done-print / skip-print) with a
combo box in the order edit screen and a completion guard.

Key decisions captured in the doc:

- The stakeholder dropped the original "order and item statuses are
  independent" requirement, so the analysis is structured around an
  explicit coupling-rules table (§3) rather than trying to reconcile a
  contradiction:
  - Order → wc-in-print: pending-print items advance to in-print
    (propagation, via the same listener used for the guard).
  - Order → wc-completed: gated — blocked if any product item is still
    pending-print or in-print.
  - All other order transitions, and any manual item-status change:
    no propagation.

- Item statuses live in WC_Order_Item meta key `_print_status` (lazy
  default = pending-print, no migration needed).

- A single new Order_Item_Status_Manager class handles UI rendering,
  POST save, propagation, and the guard via a combined listener on
  woocommerce_order_status_changed.

- Protocol imports become natural consumers: InPrint Protocol gets
  propagation for free (no code change); Delivered Protocol must
  call advance_remaining_to_done() before the order completes so the
  guard is satisfied.

- CSV export gains a prod_print_status column.

- Estimated effort: 14–20 hours for Phase 1 (classic order edit screen
  only; block-based screen tracked as Phase 2).

Open questions (§4) for stakeholder before implementation begins.

No code changed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dalibor Votruba 2 mesiacov pred
rodič
commit
746676ccb0

+ 397 - 0
studiou-wc-ord-print-statuses/docs/feature-order-item-status-analysis.md

@@ -0,0 +1,397 @@
+# Feature Analysis — Per-Order-Item Print Status
+
+**Date:** 2026-05-12 (revised after dropping the "independent statuses" requirement)
+**Target plugin version after implementation:** 1.5.0 (minor bump — new feature, additive, non-breaking).
+**Status:** Analysis / planning document. No code has been written yet.
+
+---
+
+## 1. Requirements as received
+
+> 1. Add new status for order item called `order-item-status`:
+>    - `pending-print` — order item is waiting for printing process — *initial*
+>    - `in-print` — order item is currently processing for print
+>    - `done-print` — order item was printed
+>    - `skip-print` — order item is skipped by some custom / system reason
+> 2. Add to order detail to order item possibility (combo box) to change order-item-status manually.
+> 3. When Order status is going to change to `done`, all order items must be `!= pending-print` and `!= in-print`.
+
+> *(Previous requirement #3 — "Order status and order-item-status are independent" — was withdrawn by the stakeholder; this analysis assumes order ↔ item coupling is allowed and beneficial. See §3 for the proposed coupling rules.)*
+
+---
+
+## 2. Logical revisions
+
+### 2.1 "When order status is going to change to `done`" — clarify what "done" means
+
+WooCommerce has no `wc-done` status. The plugin already adds `wc-to-print` and `wc-in-print`. The natural interpretation is the WC built-in `wc-completed`.
+
+**Proposed revision:** *"When the order status is going to change to `wc-completed`"*.
+
+### 2.2 What about non-product line items?
+
+Orders contain product items but also fee items, shipping items, coupon items, tax items, and refund items. None of these are printed.
+
+**Proposed revision:** the completion guard inspects only **product line items** (`WC_Order_Item_Product`). Other item types are not assigned a print status and never block completion.
+
+### 2.3 "Initial" value of `pending-print` — when is it set?
+
+The spec implies new items default to `pending-print`. Two strategies:
+
+- **Lazy (recommended):** the per-item meta is not written when the order is created. The `get_status()` helper returns `'pending-print'` when the meta is missing. Migration of existing orders is unnecessary.
+- **Eager:** write `pending-print` to every new item via `woocommerce_new_order_item`. Existing orders need a one-time backfill migration.
+
+**Proposed revision:** lazy default. Missing meta = `pending-print`. This avoids touching every existing order at activation time.
+
+---
+
+## 3. Coupling rules between order status and item statuses
+
+With the "independence" constraint dropped, the design space opens up. The cleanest model is **one-way coupling, order → items**: changing an order status can propagate to items; changing an item status never propagates back to the order. Within that, we need to decide *which* order-status transitions propagate and how.
+
+The proposed rules:
+
+| Order status transition | Effect on product items |
+|--------------------------|-------------------------|
+| → `wc-to-print` (Prepare to Printing) | No automatic change. Items typically already `pending-print` (lazy default). |
+| → `wc-in-print` (In Printing) | **Items in `pending-print` advance to `in-print`.** `done-print` / `skip-print` items are untouched. |
+| → `wc-completed` | **Gated, not propagating** — the transition is *blocked* if any product item is still `pending-print` or `in-print`. Operator (or protocol import) must advance items first. |
+| → `wc-cancelled` / `wc-refunded` / `wc-failed` | No automatic change. Items stay where they are (historical record preserved). |
+| → `wc-processing` / `wc-pending` / `wc-on-hold` | No automatic change. |
+| Item status changed manually | Never propagates to order. The operator drives the order status separately. |
+
+Two distinct kinds of coupling are at play:
+
+- **Propagation** (`→ in-print`): the order transition *drives* item state. The listener that handles `woocommerce_order_status_changed` runs the propagation.
+- **Guard** (`→ completed`): the order transition *requires* items to already be in the right state. If not, the transition is reverted. The same listener implements the guard.
+
+Both behaviours live in a single hook on `woocommerce_order_status_changed`. The protocol imports become natural consumers of these rules:
+
+- **InPrint Protocol** calls `$order->update_status('in-print', ...)`. The propagation rule advances pending items to `in-print` automatically. No special-case code in the protocol importer.
+- **Delivered Protocol** calls `$order->update_status('completed', ...)`. The guard would block this if items are still `pending-print` or `in-print`. The protocol importer must therefore call `advance_remaining_to_done($order)` *before* the status flip.
+
+---
+
+## 4. Open questions for stakeholder decision
+
+Before implementation begins, the following decisions should be confirmed:
+
+1. **Propagation on `→ in-print`** (§3): confirm "advance `pending-print` items to `in-print`" is the desired behaviour for manual order-status changes from the admin dropdown, bulk actions, *and* the InPrint Protocol import. Alternative: leave items untouched, require explicit per-item operations.
+2. **Audit trail:** should item-status changes write an entry to the order's activity feed? Recommendation: yes, with a brief note like *"Item #5 (Product Name): Pending Print → Done Print."*
+3. **`skip-print` reason:** is there a free-text "reason" field, or just the status? Recommendation: status only in v1.5.0; reason field as a future enhancement.
+4. **Bulk per-item operations across orders:** is there a need? Recommendation: not in v1.5.0 — single-order manual control plus protocol/propagation auto-advance covers the workflow.
+5. **CSV-export filter:** should "Prepare to Printing Export" filter to only `pending-print` items, or include everything? Recommendation: include everything, add `prod_print_status` column. Filtering can happen downstream.
+6. **Backwards-compatible behaviour for existing completed orders:** the completion guard applies only to *new* transitions to `wc-completed`. Already-completed orders are unaffected even if their items are `pending-print` (lazy default). Confirm this is acceptable.
+
+---
+
+## 5. Proposed final specification
+
+After applying §2's revisions and §3's coupling rules:
+
+1. Each order item (specifically each `WC_Order_Item_Product`) has a print status with one of four values, persisted to per-item meta key `_print_status`. Missing meta defaults to `pending-print`.
+2. The order detail screen (classic order edit) adds a **"Print Status"** column to the line-items table with a `<select>` per product row. Saving the order persists changes.
+3. **Order → item propagation:**
+   - Transition into `wc-in-print` advances every `pending-print` item to `in-print`. `done-print` and `skip-print` items are untouched.
+   - All other order-status transitions leave item statuses unchanged.
+4. **Completion guard:** transition into `wc-completed` is blocked if any product item is `pending-print` or `in-print`. Blocked transition reverts to the previous status with an admin notice listing the blocking items.
+5. **Protocol imports:**
+   - **InPrint Protocol** sets order to `wc-in-print`; items auto-propagate per rule (3a). No explicit per-item code in the importer.
+   - **Delivered Protocol** explicitly advances every `pending-print` / `in-print` item to `done-print` before setting the order to `wc-completed`. The guard is satisfied; the operator gets one summary notice.
+6. **Item-status manual changes** never propagate to the order. Operator drives the order status independently.
+7. The CSV export from "Prepare to Printing Export" gains a `prod_print_status` column reflecting each item's current status.
+8. Item-status changes (manual or propagated) generate an order note: *"Item #ID (Product name): Old Status → New Status."*
+
+---
+
+## 6. Data model
+
+### 6.1 Storage
+
+- **Meta key:** `_print_status` (underscore prefix per WC convention for internal meta).
+- **Storage layer:** `WC_Order_Item::update_meta_data()` / `get_meta()`.
+- **Underlying table:** `{$wpdb->prefix}woocommerce_order_itemmeta`. This table exists under both HPOS and legacy CPT — WC uses the same item-meta storage in both modes.
+- **No database migration required** (lazy default).
+
+### 6.2 Constants
+
+```php
+class Order_Item_Status_Manager {
+    const STATUS_PENDING = 'pending-print';
+    const STATUS_IN      = 'in-print';
+    const STATUS_DONE    = 'done-print';
+    const STATUS_SKIP    = 'skip-print';
+
+    const STATUSES_THAT_SATISFY_COMPLETION = array(
+        self::STATUS_DONE,
+        self::STATUS_SKIP,
+    );
+
+    public static function labels() {
+        return array(
+            self::STATUS_PENDING => __('Pending Print', 'studiou-wc-ord-print-statuses'),
+            self::STATUS_IN      => __('In Print',      'studiou-wc-ord-print-statuses'),
+            self::STATUS_DONE    => __('Done Print',    'studiou-wc-ord-print-statuses'),
+            self::STATUS_SKIP    => __('Skip Print',    'studiou-wc-ord-print-statuses'),
+        );
+    }
+}
+```
+
+### 6.3 API surface
+
+A new `Order_Item_Status_Manager` class exposes:
+
+| Method | Purpose |
+|--------|---------|
+| `get_status(WC_Order_Item_Product $item): string` | Returns the item's print status; defaults to `STATUS_PENDING` when the meta is missing. |
+| `set_status(WC_Order_Item_Product $item, string $status, bool $audit = true): bool` | Validates the status, writes meta, optionally appends an order note. |
+| `valid_statuses(): array` | Returns the four constants. |
+| `is_order_ready_for_completion(WC_Order $order): array{ready:bool, blocking:WC_Order_Item_Product[]}` | Used by the completion guard and admin UI. |
+| `advance_pending_to_in(WC_Order $order): int` | Used by the propagation listener on `→ in-print`. Returns count advanced. |
+| `advance_remaining_to_done(WC_Order $order): int` | Used by `Delivered Protocol` import before completing. Returns count advanced. |
+
+---
+
+## 7. Files & hooks
+
+### 7.1 New file: `includes/class-order-item-status-manager.php`
+
+Hooks registered in constructor:
+
+| Hook | Purpose |
+|------|---------|
+| `woocommerce_admin_order_item_headers` | Inject the "Print Status" column header. |
+| `woocommerce_admin_order_item_values` | Render the `<select>` per line item. |
+| `woocommerce_process_shop_order_meta` | Read `$_POST['print_status'][$item_id]`, persist via `set_status()`. Runs after WC's own item processing. |
+| `woocommerce_order_status_changed` (priority 5) | Combined propagation + completion guard (see §8). |
+
+### 7.2 Modified: `includes/class-db-manager.php`
+
+- `import_inprint_protocol()`: no functional change — propagation happens automatically via the listener when `$order->update_status('in-print', ...)` fires. Optionally surface the advanced count in the admin notice: *"3 line items advanced to In Print."*
+- `import_delivered_protocol()`: **before** calling `$order->update_status('completed', ...)`, call `Order_Item_Status_Manager::advance_remaining_to_done($order)` so the guard is satisfied. Surface the advanced count in the import-summary notice.
+- `get_orders_for_printing()`: extend the SELECT to surface item-level print status. Join `{$wpdb->prefix}woocommerce_order_items` (the item row) and `{$wpdb->prefix}woocommerce_order_itemmeta` (the `_print_status` meta) on `order_item_id`. Add `prod_print_status` to the CSV output. Note: the existing query groups by `(order, product, variation)` — multiple line items in one group would need a deterministic pick (e.g., `MIN()` again, or join via `order_products.order_item_id` if the lookup table exposes it).
+
+### 7.3 Modified: `studiou-wc-ord-print-statuses.php`
+
+Add the new manager to `load_dependencies()` and `initialize_managers()`, identical to the existing pattern. Bump `STUDIOU_WC_OPS_VERSION` to `1.5.0`.
+
+### 7.4 Modified: `includes/class-bulk-actions-manager.php`
+
+No code change. Bulk actions `"Set Status to Prepare to Printing"` and `"Set Status to In Printing"` already call `$order->update_status(...)` — the propagation listener handles items automatically when the transition is to `in-print`. The "Prepare to Printing" path doesn't propagate (per §3).
+
+### 7.5 Modified: `README.md`, `CLAUDE.md`, `docs/translations.txt`, `languages/studiou-wc-ord-print-statuses-cs_CZ.po`
+
+- README: new "Order item statuses" feature section + 1.5.0 changelog entry + coupling rules table from §3.
+- CLAUDE.md: extend the manager-pattern list with the new manager + Recent Changes entry.
+- Translations: add the four status labels, "Print Status" column header, guard error message, audit-note format, and the protocol auto-advance summary strings.
+
+---
+
+## 8. Combined propagation + completion guard
+
+A single listener on `woocommerce_order_status_changed` handles both behaviours. Pseudocode:
+
+```php
+public function on_order_status_changed($order_id, $from, $to, $order) {
+    // Re-entrancy guard: a guard-revert below fires this hook again. Skip
+    // the recursive invocation.
+    if (self::$inside_self_revert) {
+        return;
+    }
+
+    if ($to === 'in-print') {
+        $advanced = $this->advance_pending_to_in($order);
+        if ($advanced > 0) {
+            UtilsLog::log("Order #{$order_id}: advanced {$advanced} item(s) to in-print on order → in-print");
+        }
+        return;
+    }
+
+    if ($to === 'completed') {
+        $check = $this->is_order_ready_for_completion($order);
+        if ($check['ready']) {
+            return;
+        }
+        self::$inside_self_revert = true;
+        try {
+            $order->update_status(
+                $from,
+                __('Cannot complete: product line items still pending print. Resolve item statuses first.', 'studiou-wc-ord-print-statuses')
+            );
+        } finally {
+            self::$inside_self_revert = false;
+        }
+        UtilsLog::message(
+            sprintf(
+                __('Order #%1$d completion blocked — %2$d product items not yet "Done Print" or "Skip Print".', 'studiou-wc-ord-print-statuses'),
+                $order_id,
+                count($check['blocking'])
+            ),
+            'error'
+        );
+    }
+}
+```
+
+**Caveats:**
+
+1. `woocommerce_order_status_changed` fires *after* the change is committed. Reverting via `update_status` is post-hoc — the order shows the reverted state on the next page load. Slightly disorienting but workable, and the admin notice explains it.
+2. The static `$inside_self_revert` flag prevents infinite recursion when the revert itself fires the hook.
+3. For cleaner UX on the admin form path, a complementary interception in `woocommerce_admin_process_order_object` can validate **before** save. The post-hoc revert still covers programmatic / API / protocol paths. Belt-and-braces.
+
+---
+
+## 9. UI mockup (text)
+
+In the order edit screen's Items meta box, the table grows by one column:
+
+```
+| Item                  | Cost   | Qty | Total  | Print Status         |
+|-----------------------|--------|-----|--------|----------------------|
+| Product A (variation) | 100.00 |  2  | 200.00 | [Pending Print  ▼]   |
+| Product B (variation) |  50.00 |  1  |  50.00 | [Done Print     ▼]   |
+| Shipping              |      — |  —  |  10.00 | —                    |
+| Coupon: SUMMER10      | -20.00 |  —  | -20.00 | —                    |
+```
+
+Non-product items show `—` and aren't editable.
+
+Optional v1.5.0 sweetener: a one-line summary above the table — *"Print readiness: 3 of 4 items ready (1 pending)."*
+
+---
+
+## 10. Edge cases & open behaviour decisions
+
+| Scenario | Proposed behaviour |
+|----------|---------------------|
+| Order has 0 product items | Completion allowed (vacuously satisfies the guard). |
+| Order has only refunds / shipping / fees | Completion allowed. |
+| Existing `wc-completed` order with items in `pending-print` | No effect — the guard only fires on the *transition* into `completed`, not on stored state. |
+| Manual order status flip Pending → Completed (skipping in-print) | Guard fires. Items are still `pending-print` → blocked. Operator must advance items or use protocol imports. |
+| Order in `wc-in-print` reverted to `wc-processing` then back to `wc-in-print` | First revert: no item change (per §3). Second forward: pending items advance again (no-op since they're already `in-print`). Done items stay done. |
+| Item is removed from order after being set to `done-print` | The meta is deleted along with the item. No orphan record. |
+| Item status changed *after* order is `completed` | Allowed. Order doesn't revert. |
+| Bulk action "Set Status to In Printing" on 100 orders | Each order's pending items propagate to `in-print` via the listener. |
+| Multiple `wc-in-print` ↔ `wc-to-print` ping-pong | Each → `in-print` advances any remaining `pending-print` items. Items previously moved stay in `in-print`. |
+
+---
+
+## 11. Test plan
+
+### 11.1 Unit-style scenarios
+
+1. **Default value:** new order item has no `_print_status` meta; `get_status()` returns `'pending-print'`.
+2. **Set status:** `set_status($item, 'in-print')` writes the meta and (with `$audit=true`) appends an order note.
+3. **Invalid status:** `set_status($item, 'foo')` rejects and returns `false` without writing.
+4. **Completion guard ready:** all items in `done-print` or `skip-print` — `is_order_ready_for_completion()` returns `{ready:true}`.
+5. **Completion guard blocked:** at least one item in `pending-print` or `in-print` — returns `{ready:false, blocking:[…]}`.
+6. **Non-product items ignored:** an order with one product item (`done-print`) and one shipping item — guard returns ready.
+7. **`advance_pending_to_in`:** order with items `[pending, in, done, skip]` → result has items `[in, in, done, skip]`. Count = 1.
+8. **`advance_remaining_to_done`:** order with items `[pending, in, done, skip]` → result `[done, done, done, skip]`. Count = 2.
+
+### 11.2 Integration
+
+1. **Admin UI manual change:** open an order with three items, change one to `done-print`, click Update, reload → meta persisted, audit note added.
+2. **Propagation:** change order status to `wc-in-print` via the admin dropdown → all `pending-print` items in the order are now `in-print`. Order note from `update_status` plus per-item audit notes.
+3. **Completion guard via admin:** with one item still `pending-print`, change order status to `wc-completed`, click Update → order reverts to previous status (visible after reload), admin notice shows the block reason.
+4. **Completion guard via programmatic call:** `wp wc shop_order update <id> --status=completed` on an order with `pending-print` items → status reverts.
+5. **InPrint Protocol import:** prepare a CSV with one `order_no`, run the import → order is in `in-print`, all the order's `pending-print` items advanced to `in-print` via the listener, `done-print` and `skip-print` items untouched. Import notice mentions advanced count.
+6. **Delivered Protocol import:** prepare a CSV with one `order_no`, run the import → items advance to `done-print` first, then order flips to `completed`. Guard is satisfied. Import notice mentions advanced count.
+7. **CSV export:** "Prepare to Printing Export" bulk action — output contains a `prod_print_status` column with per-item values.
+
+### 11.3 Regression
+
+1. The "Set Status to Prepare to Printing" bulk action still works without touching items (no propagation on `→ to-print`).
+2. The "Set Status to In Printing" bulk action now also propagates items (new behaviour — expected).
+3. Existing completed orders are unaffected by the new guard.
+4. The Print Information panel on the order edit screen still renders.
+5. The custom orders-list columns still render.
+6. The order search by external reference still works.
+
+---
+
+## 12. Rollout
+
+### 12.1 Versioning
+
+- New plugin version: **1.5.0** (minor — feature addition, no breaking changes).
+- `STUDIOU_WC_OPS_VERSION` constant updated accordingly.
+
+### 12.2 Activation behaviour
+
+- No database migration. Lazy defaults handle existing items.
+- No new tables. The `woocommerce_order_itemmeta` table is already created by WC.
+
+### 12.3 Deactivation behaviour
+
+- Same policy as today: meta keys are not cleaned up. Reactivation preserves all data.
+
+### 12.4 Internationalisation
+
+~12 new translatable strings:
+
+- 4 status labels: `Pending Print`, `In Print`, `Done Print`, `Skip Print`.
+- 1 column header: `Print Status`.
+- 1 placeholder for non-product items: `—` (literal, not translated).
+- 1 completion-guard order note: `Cannot complete: product line items still pending print. Resolve item statuses first.`
+- 1 admin notice: `Order #%1$d completion blocked — %2$d product items not yet "Done Print" or "Skip Print".`
+- 1 audit-note format: `Item #%1$d (%2$s): %3$s → %4$s.`
+- 2 protocol-auto-advance order notes: `%d items advanced to In Print by order-status change.`, `%d items advanced to Done Print by Delivered Protocol import.`
+- 1 readiness summary (optional UI sweetener): `Print readiness: %1$d of %2$d items ready (%3$d pending).`
+
+### 12.5 Documentation
+
+- README: new "Order item statuses" feature section + coupling rules table + 1.5.0 changelog entry + Known Limitations updated (block-based screen still unsupported).
+- CLAUDE.md: new manager added to the manager-pattern list + Recent Changes entry.
+- New review doc (post-release): `docs/revise-1.5.0.md` once the feature lands.
+- `docs/feature-order-item-status-analysis.md` (this document) → archive or supersede after implementation.
+
+### 12.6 Phasing (suggested)
+
+- **Phase 1 (v1.5.0):** core feature — data model, admin UI, propagation listener, completion guard, Delivered Protocol explicit advance, CSV export column. Classic order edit screen only.
+- **Phase 2 (v1.5.x or later):** AJAX live status changes (no full page reload), bulk-change items across orders, optional `skip-print` reason field, block-based order edit screen support.
+
+---
+
+## 13. Effort estimate
+
+Rough sizing for Phase 1:
+
+| Area | Effort |
+|------|--------|
+| `Order_Item_Status_Manager` class (data model + admin UI + combined propagation/guard listener) | ~6–10 hours |
+| `Studiou_DB_Manager` integration (Delivered Protocol advance, CSV column with new join) | ~2–3 hours |
+| Bootstrap + manager wiring + version bump | ~30 minutes |
+| README / CLAUDE.md / translations / .po | ~2 hours |
+| Test pass (manual scenarios in §11) | ~3–4 hours |
+| **Total** | **~14–20 hours** |
+
+Phase 2 items add ~6–10 hours each depending on scope.
+
+---
+
+## 14. Risk register
+
+| Risk | Likelihood | Impact | Mitigation |
+|------|------------|--------|------------|
+| Listener recursion (propagation → save → propagation, or guard-revert → revert → revert) | Medium | High | Static `$inside_self_revert` flag; propagation only fires on `→ in-print` not on every save. |
+| Existing orders break on first edit because meta is missing | Low | Low | Lazy default handles this — `get_status` returns `pending-print` for missing meta. |
+| Operator surprise: clicking "Set Status to In Printing" silently advances items | Low | Low | Documented in README; per-item audit notes show what happened. |
+| Block-based order edit screen doesn't render the new column | Medium | Low | Documented as a known limitation since 1.4.1; carried forward. |
+| `_print_status` meta key collides with another plugin | Very low | Medium | If collision found, fall back to a namespaced key (`_studiou_print_status`). |
+| Delivered Protocol "advance to done" advances items the operator intended to leave in `skip-print` | None | — | `skip-print` already satisfies the completion guard; the advance helper only touches `pending-print` / `in-print`. |
+
+---
+
+## 15. Recommendation
+
+Implement Phase 1 as described above, subject to stakeholder confirmation of the §4 open questions — particularly:
+
+- Open question 1 (propagation on `→ in-print`). The proposed design assumes "yes, advance pending items". This is the workflow-consistent choice, but it does change the behaviour of the existing **bulk action "Set Status to In Printing"** (previously order-only, now also touches items). If the stakeholder prefers the bulk action to remain strictly order-only, the propagation rule can be limited to specific paths (e.g., only the InPrint Protocol import) — but that re-introduces some of the awkwardness the old §2.5 grappled with.
+
+The shape of the design with requirement #3 dropped is materially cleaner than the original analysis: a single listener implements both behaviours, the protocol-import code paths are minimally changed, and the rules can be summarised in one table (§3).
+
+---
+
+*End of analysis.*