Commit graph

97 commits

Author SHA1 Message Date
af4cdc66da feat(collection-confirm): spot a photo on the wrong PO and move it
Drivers photograph invoices per item and can't see which order a photo
lands on. B&R invoice 00282979 (stock order PO26100702STK) ended up on
the thinners line of PO202610017BLY; the AI read "PO26100702STK" off it
but the card only said "not found".

- The card list now carries each read's po_refs and source file, and sets
  ai_doc.other_po when the document names a PO that exists and isn't the
  row's PO (none named, or this card's PO among them: no hint).
- PO card: "Photo may be for <PO>" in the header; when open, "Invoice <no>
  is for <PO>, not this PO" with a Move photo button. Nothing moves on its
  own.
- POST /api/v1/collection-confirm/move-photo (browser session) →
  movePhotoToPo: copies the photo to the target (a collected line of a
  customer PO, or the stock purchase's single photo slot — refused when
  taken), removes it from the source, deletes the AI's read of it and the
  checks built on it so it is re-read where it now belongs.
- normalizePoReference moves to the client-safe src/lib/po-reference.ts
  (re-exported from the matching service).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:08:47 +02:00
802565d2d8 feat(collection-confirm): check printed prices on delivery notes; show AI reading notes
Plumblink hands out delivery notes with prices on them. The Price tick
was always grey on a delivery note, so a card could go purple without
its prices ever being checked, and the AI's reading notes ("delivery
note, not a tax invoice", "year not printed") were never shown.

- Price tick: compare whenever the document line has a price, invoice
  or delivery note; grey only when no price is printed. The AI still
  only corrects a cost from a tax invoice.
- ai_doc now carries the read's notes; cardNotes() unions them per card
  and the AI findings box lists them under "Reading notes" (the box now
  shows when there are notes but no findings).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:50:27 +02:00
d73fb6f0ab feat(collection-ai): read invoice discounts and set the discounted cost
HYCO (I009753) prints full prices on the lines and "Discount 25.00%" in
the totals; Swagelok (622831) has a "Disc %" column on each line. The AI
compared our cost (already the discounted price) with the printed price,
so the Price tick went red on both.

- The read now captures a line's discount_percent and a whole-document
  doc_discount_percent (prompt rule 5b) and stores net_unit_price on each
  line (both discounts stacked).
- The Price tick compares the cost with the price after discount; the
  tooltip and the document-lines panel spell it out
  ("R15.10 less 25% invoice discount = R11.33").
- Owner's call: when a "sure" tax-invoice line has a discount and our
  cost isn't the discounted price, the AI sets the cost to it (customer
  lines through updateOrderItemCost, which adds a cost note; stock lines
  through updateStockPurchaseItem) and records why in ai_check.cost_changed,
  shown in purple under the line. No discount, a delivery note or a
  "likely" match: the cost is never touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:18:21 +02:00
cba2d84549 docs(collection-ai): runbook tick table, audit scope; spec content_hash index is non-unique
F2: tick table (SKU green via the code match incl. AI fills, grey per tick,
pairing failure -> all grey, different product -> red), stock lines use the
line SKU, Add to POS needs a SKU, SKU fills audited for order lines only.
F3: content_hash is a non-unique index (identical uploads share a hash,
skipped PDFs have an empty hash) - matches the migration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 10:21:25 +02:00
8c3cfd45fc feat(collection-ai): settings section, runbook
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 09:55:44 +02:00
3e37ae482f docs(collection-confirm): AI checks implementation plan
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 01:04:42 +02:00
3624d87801 docs(collection-confirm): AI checks design spec
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 01:00:49 +02:00
3091ac94de docs(quote-assistant): runbook accuracy, MCP tool listed in API docs
- Runbook: pre-migration settings don't persist (not "saves fail"),
  eligible statuses, 15 lines per quote, audit attribution, clone/template
  behaviour, supplier kept, doubts dot, confidence guidance (Medium is the
  default; raise to High if reps often change AI prices).
- quotes.assistant_fill added to docs/api-mcp-layer.md,
  docs/audit/api-mcp-coverage.md and the Giellie skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 23:42:44 +02:00
a9160de1d6 fix(quote-assistant): retry unanswered lines, bound and serialise ticks
- decideWithAi throws on stop_reason max_tokens instead of returning a
  partial answer; fillQuote marks a requested line the AI did not answer
  as error (retried after 1 h), never a permanent no_match.
- QUOTE_MAX_LINES 30 -> 15; the tick also caps lines per quote so the
  60-line budget reaches other quotes.
- runAssistantTick stops starting quotes after a 90 s time budget and
  returns reason running while a newer start than the last summary is
  under 10 minutes old (lease).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 23:26:28 +02:00
144971779f feat(quote-assistant): settings section, n8n tick, runbook
Quote assistant card in Settings, AI (on/off, interval, min confidence,
editable prompt with reset, last-run line); parseSettingsForm handles the
qa_* fields. docs/quote-assistant.md has the runbook and the n8n tick
workflow spec; AGENTS.md gets a short section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 20:10:02 +02:00
bb06165318 feat(quote-assistant): fill service, tick, counts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:29:16 +02:00
7d5f4de7d8 docs(quotes): AI quote assistant implementation plan
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 19:00:26 +02:00
681dc29435 docs(quotes): AI quote assistant design spec
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 18:48:48 +02:00
8d83065964 feat(giellie): tighten the agent tool policy and MCP surface
Aligns the tool policy, the system prompt, the MCP route and the skill
doc so they describe the same boundary, with tests pinning the policy
and prompt text.

The docs and the executable policy had drifted apart — the skill doc
advertised capabilities the policy does not grant, which is worse than
not documenting them: an agent reading the doc will plan around a tool
it isn't allowed to call.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-16 00:44:52 +02:00
6c8f63661a fix(mcp): validate set_pricing actor and row ids; tighten pricing prompt
actor.id must be a 15-char user id (stock_ledger.created_by is a relation to
users; a non-user id left the cost patched but unaudited). Each updates[i].id
is validated, actor.name defaults to the actor id, and the Giellie prompt now
says to pass both selling_price and markup on create and to read the item
before a partial price change. Adds tests for null / numeric-string prices
and the explicit markup:0 default-markup behaviour.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 01:09:43 +02:00
73127f10cc docs(mcp): document stock_items.set_pricing and create pricing fields
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 01:02:44 +02:00
662610ca28 docs(giellie): add agent design spec and implementation plan
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 23:31:57 +02:00
7555196166 feat(audit): implement audit trail for delivery notes and orders
- Added an audit trail feature that logs every create, update, and delete action on delivery notes and orders, capturing detailed changes per field.
- Introduced the `AuditTimeline` component to display the history of changes for delivery notes and orders, enhancing traceability.
- Updated the `page.tsx` files for delivery notes and orders to fetch and display audit logs, ensuring users can view the history of modifications.
- Enhanced the `package.json` with a new migration script for setting up the audit log functionality.

This feature improves accountability and transparency in the management of delivery notes and orders.
2026-09-30 01:48:44 +02:00
cd359b75a9 feat(quotes): split attachments into internal vs outbound with operator upload UI
Splits the quote attachment model along the seam that actually matters:
'operator-only references' (drawings the operator consulted, supplier
emails they filed away) vs 'customer-facing files' (supplier quotes,
drawings, NDAs that need to ride along on the email).

Schema (PB): new `internal_attachments` + `outbound_attachments` fields
on the `quotes` collection, maxSelect 10 each. Existing `attachments`
field kept for back-compat but is no longer the source of truth for
outbound emails.

API:
- GET/POST/DELETE /api/v1/quotes/[id]/internal-attachments[/{filename}]
- GET/POST/DELETE /api/v1/quotes/[id]/outbound-attachments[/{filename}]
- POST /api/v1/quotes/[id]/attachments/upload kept for legacy `attachments`

MCP: `quotes.send_email` description now correctly states
`selectedAttachmentIds` are PB file tokens from `outbound_attachments`
(supplier quotes, drawings, NDAs), not IDs of the legacy `attachments`
collection.

Frontend: `ProcessOutboundAttachmentsCard` component lets the operator
upload/remove customer-facing files during the process page; approval +
process pages now read the new fields.

Outbound Send workflow (deployed as `PIEAkPYYYZLGl6Pj`):
- Old workflow (id `WF_Email_Send_SMTP`) and stale repo file
  (`WFDASH — Quote Outbound Send.json`) replaced.
- New revision intersects `quotes.outbound_attachments` with
  `email_outbound_attachment_ids`, downloads each from
  `/api/files/quotes/<id>/<token>`, and emits
  `options.attachments: [{name, content, type}]` consumed by
  `Send Email (SMTP)` (PO Send pattern).
- Failure path flipped from `send_failed` to `mail_failed` so
  `retryQuoteEmail` can find failed sends (it only accepts the
  latter). Previously failed sends were stranded.

Email Monitor (v5) workflow fixes:
- Reply-branch auth: any authenticated request now passes through;
  pre-fix bug rejected branches that the IMAP trigger hadn't seen yet.
- Reply detection: bulletproof subject regex
  (/Q-?\d{4}-?\d{2}-?\d{3}/) accepts both legacy `Q-2026-09-246`
  and current `Q202609246` formats; canonicalised digits-only for
  PB `~` substring match.

Delivery notes: new pricing endpoint at
/api/v1/delivery-notes/items/[id]/pricing + service-layer methods.

Snapshots kept for forensics: PRE-FIX-REPLY-{BRANCH-AUTH,DETECTION}.json
and push-payload.baseline.json are the previously-deployed workflow
shapes, retained so we can diff/rollback if regression hits.

Verified:
- PUT workflow PIEAkPYYYZLGl6Pj -> 200, active, 25 nodes
- quotes-service.test.ts: 117 pass (4 pre-existing failures unchanged)
- mcp/route.test.ts: 118 pass (2 pre-existing failures unchanged)
- node --check on new Code node JS passes

Docs: docs/quotes-outbound-attachments-deploy.md covers the deploy
procedure; docs/api-mcp-layer.md description sync.
2026-09-09 13:43:56 +02:00
b9d30c8e6f fix(quotes-intake): clamp email_body to PB's 5000-char cap
PocketBase treats `max: 0` on a text field as "use the default 5000-char cap", not unlimited. A Redpath reply with a 5029-char body 400'd on every 2-minute poll for hours on 2026-09-08, wedging every RFQ behind it because the failed email stayed UNSEEN.

Added clampEmailBody (with a truncation marker) and routed email_body writes through it so oversized replies still become quotes instead of blocking the queue. The untruncated body remains in the mailbox, and attachments carry the detail. Raise this cap in lockstep with any PB admin change to the field's max.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 10:28:20 +02:00
6fd11f4af0 feat(rep-visits): FleetAI tracker adapter, nearby-customer matching, stop detection
Groundwork for the rep visit check-in feature: a rep taps "I'm on site",
the vehicle's tracker position surfaces which customers are there, and
the visit is logged against them.

Pure/unit-testable layers only — no PocketBase writes and no UI yet,
both of which are blocked on schema that has to be added in the PB
admin first. Design doc: docs/superpowers/specs/2026-09-05-rep-visit-check-in-design.md

- lib/visit-matching.ts   rankNearbyCustomers: radius match around a
                          point, rep's own customers first
- lib/visit-stops.ts      detectStops: breadcrumb trail -> stops.
                          Anchor-based clustering rather than a running
                          centroid, which would let a slow crawl chain
                          into one bogus stationary stop
- lib/tracker-parsing.ts  Netstar FleetAI response decoding
- lib/server/tracker-service.ts
                          FleetAiAdapter + FakeTrackerAdapter behind a
                          TrackerAdapter seam. The fake is auto-selected
                          when no credentials are configured, so the rest
                          of the feature builds and tests without vendor
                          access.
- lib/geo.ts              isRealGeoPoint, lifting the Null-Island guard
                          that was inlined identically in customers/[id]
                          and companies/[id]

Three FleetAI conventions drive real code here and are each pinned by a
test: errors arrive as HTTP 200 with a failure envelope; "--" means
"unavailable" and is not null (and for IGN, not false); timestamps are
platform-local UTC+2 with no offset marker, so parsing them naively puts
every fresh fix two hours in the past.

FleetAI has no position-history endpoint, so the design polls
getTokenBaseLiveData (whole fleet in one call) and keeps its own trail.
scripts/fleetai-probe.mjs is a throwaway read-only probe to confirm the
three account-shaped assumptions before more is built on top.

102 tests pass. The 9 pre-existing failing test files elsewhere in the
suite were verified identical on a stashed tree and are unrelated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 14:22:28 +02:00
e0ce1310e0 docs(pos): add implementation plan for the slip layout editor 2026-09-04 13:20:16 +02:00
024168f90d docs(pos): add design spec for the slip layout editor
Covers the reorderable block-list editor for sale/delivery/cash-up
slips, per-letterhead persistence, and the delivery-note pricing
default, worked out via brainstorming with the visual companion.
2026-09-04 12:42:45 +02:00
064145e5b7 refactor(sops): streamline SOP documents for roles, consolidating content into quickstart guides for easier reference 2026-09-03 17:57:49 +02:00
aed3f5c861 feat: implement discount functionality in POS system
Added support for discounts in the POS checkout process, allowing operators to apply either a fixed amount or a percentage off the gross total. Updated the state management to include discount details and modified the receipt and cart rendering to display pre- and post-discount values. Enhanced the checkout API to handle discount inputs and ensure proper calculations. Updated relevant tests to cover new discount logic.
2026-09-03 12:19:21 +02:00
0984b7513e docs: implementation plan for DN items expand
Single-task, single-file plan: add chevron + items panel to
DeliveryNoteRowComponent on /deliveries. Lifts expand state to the
page (Set<string>), passes expanded + onToggle + items down. Items
filtered client-side from page data; empty-state fallback to
/delivery-notes/[id].

7 steps: imports, locate call site, page-level state, prop-drill,
update component signature + render chevron + items panel, smoke check
via agent-browser, commit.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-01 12:03:35 +02:00
66e2fb9856 docs: clarify unit suffix handling in DN items panel header
The 'Total {sumQty}{unitSuffix}' header line now explicitly documents
how mixed / missing units are handled: suffix is omitted when all
items have empty/null units (operator defaults to 'EA'); when units
are mixed, no suffix is shown; when all items share a non-EA unit
(e.g. BOX), the suffix is shown.

Self-review pass; no other changes.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-01 12:01:42 +02:00
b39614b4da docs: spec for /deliveries DN items expand
Click-to-expand on each delivery-note row reveals an inline items
panel (description + qty) below the row. Operator can match the items
against the printed DN paper in their hand before loading. Pure
client-side render — items already loaded by /api/v1/deliveries are
filtered by delivery_note == dn.id. Empty state with fallback link to
/delivery-notes/[id] for DNs whose items aren't in the page slice.

Single-file edit on src/app/(app)/deliveries/page.tsx. No server,
schema, API, or MCP changes.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-01 12:01:12 +02:00
57584798f3 docs: include rep-scoped list filter plan + summary
The plan + summary landed locally during the implementation but were
not committed alongside the code. Both documents describe the
rep-scoped Orders / Quotes / Invoicing / Delivery Notes list filter
work that already shipped (commits 8faa443, ed07617, 29eb003, 9cf8e39
etc).

- 2026-08-31-rep-scoped-list-filter.md — the implementation plan
- 2026-09-01-rep-scoped-list-filter-SUMMARY.md — post-implementation
  summary with the commit log + verification notes + the known
  limitation (Orders/Quotes tab counts are unfiltered for reps)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-01 02:11:28 +02:00
b3965b1454 docs: implementation plan for compact DN row + order age badge
Three bite-sized tasks with full code:
  1. TDD the order-age util (test → impl → run)
  2. Wire OrderAgeBadge into /orders (replace bare date)
  3. Enrich /deliveries DN row subline (customer/order/paperclip)

All UI/rendering only. No server, no schema, no MCP changes.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-01 01:57:47 +02:00
3fc9c576bf docs: spec for compact DN row + order age badge
Two small, independent rendering improvements for /deliveries and /orders:

  1. /deliveries — each delivery-note row gets a compact subline with
     customer name, company name, parent order number, and a signed-copy
     indicator (paperclip + filename tooltip). All data already on the
     row payload — no server-side changes.

  2. /orders — order card right-aligned metadata slot gets a colour-
     coded age badge (today / Xd old) replacing the bare date string.
     New src/lib/order-age.ts as a pure function with bucket thresholds
     (green <3d, amber 3-7d, orange 8-14d, red 15+d) and a unit test.

No PB schema changes. No /api/v1 route changes. No MCP tool changes.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-01 01:56:28 +02:00
5c210546e9 docs: add implementation plan for rep dashboard (dashboard 2)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-01 01:31:57 +02:00
cc6f63dabb docs: add design spec for rep dashboard (dashboard 2)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-01 01:25:53 +02:00
Claude
afa4c070b3 docs(stock): reconcile spec with shipped design
Two spec-vs-implementation drifts caught by the final review:
- Move 'per-row validation → 200 with reason in results[]' out of the
  'Reject 400' list. The route enforces body shape (json / empty /
  too-many / bad id / missing actor) as 400; the service enforces
  forbidden_field / non-finite / not_found / pb_error per row so one
  bad sibling never aborts the rest.
- Move the 'realtime-conflict banner' from Page-behaviour to Out of
  scope (the implementation deferred it; the spec still listed it).
2026-08-31 17:19:12 +02:00
Claude
b6a76be75b docs(stock): implementation plan for inline pricing edit 2026-08-31 16:17:10 +02:00
Claude
7c3b8f642a docs(stock): bulk cap 100 + clarify selling-derive precedence 2026-08-31 16:14:29 +02:00
Claude
84a97ac7b2 docs(stock): design spec for inline pricing edit on /stock 2026-08-31 16:13:44 +02:00
bef2a08299 docs(pos): record created PB collections, live test results, catalog paging
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-31 02:25:28 +02:00
8e6a6deac9 docs(pos): record implementation deviations and rollout blockers
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-31 01:51:56 +02:00
a73f3b3f97 fix(orders): update order_number collision-checking logic
Refine the handling of order_number values in the MCP API. Custom free-text order_numbers are now allowed to repeat across orders without triggering collision checks, while only values formatted as ORD-YYYY-MM-NNN will be subject to collision verification. Update tests to reflect this new behavior and ensure proper functionality.
2026-08-31 01:24:56 +02:00
926be6c57b docs(pos): add implementation plan for WFSALES POS
Backend-first TDD plan (pos-auth, pos-service, /api/v1/pos/* routes)
followed by relocating and rewiring the existing static POS mockup
into public/pos/, removing the hardcoded PB superuser credentials.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-31 00:03:25 +02:00
0ba9e59f82 docs(pos): add design spec for WFSALES POS app
Scopes hardening the existing POS mockup (superuser creds removed,
catalog moved to stock_items, checkout wired to stock_ledger) as a
route inside WFDASH-WEBAPP rather than a separate service.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 23:50:56 +02:00
4d95b7af8c docs: non-invoiceable extras design + plan, quantity-handling audit
Three documents behind the two features on this branch:

- specs/2026-08-30-non-invoiceable-order-extras-design.md — the design
  the implementation followed, including why the flag must be named for
  the exception (a positively-named field defaults to false and would
  mark every existing row non-billable the moment it is created).
- plans/2026-08-30-non-invoiceable-order-extras.md — the task-by-task
  plan, now fully implemented.
- specs/2026-08-30-quantity-handling-audit.md — the order_qty /
  quantity audit that produced the preceding fix, plus the partial
  collection findings that are still open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 18:28:44 +02:00
cb2beb4016 docs(orders): record sweep checkpoint outcome, keep 90-day window 2026-08-30 12:13:29 +02:00
11535fd432 docs(orders): flag the plan as partly-implemented, fix Task 7 paste-traps 2026-08-30 08:26:57 +02:00
5a8b8575b7 docs(orders): handoff doc for outstanding order-linking work 2026-08-29 23:53:30 +02:00
0083199ed2 docs(orders): spec + plan for delivery-note repeat-order detection 2026-08-29 23:51:52 +02:00
0979f6bc10 docs(orders): correct the possible-tier fixture in the plan
The original sample scored 0.222 Jaccard — below the 0.3 candidate
floor — so it would have been dropped rather than tiered. Verified
0.333 for the replacement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 11:18:52 +02:00
88fa8e978e docs(orders): add implementation plan for quote auto-linking
13 TDD tasks across two phases. Phase 1 (backend) ends with orders
matched automatically at intake plus a backlog sweep; Phase 2 surfaces
the paired quote line's note and attachments on both order pages.

Resolves the spec's two open questions: `after` is stable in
next/server on Next 16.2.6, and PocketBase date filters take
`.toISOString()`.

Two deviations from the spec, both noted in the plan: line pairing
hooks into the existing setOrderQuote rather than a new
linkQuoteToOrder, and the per-line context extends the existing
matched-attachments response rather than adding an endpoint.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 10:59:37 +02:00
f1c07e8682 docs(orders): spec order↔quote auto-linking and per-line quote context
Design for closing three gaps in the existing order↔quote matcher:

  - The matcher only runs when an operator clicks it, so the ~85% of
    orders that arrive against a quote stay unlinked. Adds a call from
    createOrder plus a catch-up sweep for the backlog.
  - order_items.quote_item is only written when an order is created
    from a quote, so post-hoc links never pair lines. Adds persistence
    for confident pairs.
  - findMatchedQuoteItem re-guesses the pairing at render time using
    exact/substring matching, so buyer notes and per-line attachments
    silently vanish on any wording difference. Replaced with the
    tokenised matcher already in the repo.

Fuzzy candidates are windowed to 90 days before the order's own date
(widening to 12 months only when nothing clears the threshold);
exact-identifier lookups stay unwindowed.

No PocketBase schema changes required.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 10:49:06 +02:00