Add OTC sales UI with direct sales support

- Create OTC UI form at public/otc/index.php
- Add API endpoint public/api/otc-order.php
- Extract shared DB connection to includes/db.php
- Add migration for OTC products (0006_phase1_otc_products.sql)
- Support order_source='direct' with automatic DIR- reference generation
- Include billing address capture with default values
- Add payment methods cash and paypal for direct sales
- Implement stock allocation and inventory management
This commit is contained in:
2026-04-06 19:55:24 +02:00
parent d2943b446b
commit d52b6953ed
4 changed files with 1091 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
BEGIN;
-- OTC products for direct sales
INSERT INTO product (sku, name, status, uom) VALUES
('SHIITAKE-50ML', 'PURE Shiitake Extrakt Tinktur 50ml', 'active', 'unit'),
('REISHI-50ML', 'PURE Reishi Extrakt Tinktur 50ml', 'active', 'unit'),
('LIONSMANE-50ML', 'PURE Lion''s Mane Extrakt Tinktur 50ml', 'active', 'unit'),
('CHAGA-50ML', 'PURE Chaga Aroma Extrakt Tinktur 50ml', 'active', 'unit')
ON CONFLICT (sku) DO UPDATE SET
name = EXCLUDED.name,
status = EXCLUDED.status,
uom = EXCLUDED.uom,
updated_at = NOW();
-- Create sellable items for OTC products
INSERT INTO sellable_item (item_code, display_name, status)
SELECT
'OTC-' || p.id,
p.name,
'active'
FROM product p
WHERE p.sku IN ('SHIITAKE-50ML', 'REISHI-50ML', 'LIONSMANE-50ML', 'CHAGA-50ML')
ON CONFLICT (item_code) DO UPDATE SET
display_name = EXCLUDED.display_name,
status = EXCLUDED.status,
updated_at = NOW();
-- Link sellable items to products
INSERT INTO sellable_item_component (sellable_item_id, product_id, qty_per_item)
SELECT
si.id,
p.id,
1.0
FROM sellable_item si
JOIN product p ON p.name = si.display_name
WHERE p.sku IN ('SHIITAKE-50ML', 'REISHI-50ML', 'LIONSMANE-50ML', 'CHAGA-50ML')
ON CONFLICT (sellable_item_id, product_id) DO UPDATE SET
qty_per_item = EXCLUDED.qty_per_item,
updated_at = NOW();
-- Ensure we have current lots for OTC products
DO $$
DECLARE
prod_record RECORD;
current_lot_id BIGINT;
open_lot_id BIGINT;
BEGIN
FOR prod_record IN
SELECT id FROM product
WHERE sku IN ('SHIITAKE-50ML', 'REISHI-50ML', 'LIONSMANE-50ML', 'CHAGA-50ML')
LOOP
-- Check if current lot exists
SELECT id INTO current_lot_id
FROM stock_lot
WHERE product_id = prod_record.id
AND status = 'current'
LIMIT 1;
IF current_lot_id IS NULL THEN
-- Check for open lot to promote
SELECT id INTO open_lot_id
FROM stock_lot
WHERE product_id = prod_record.id
AND status = 'open'
ORDER BY id
LIMIT 1;
IF open_lot_id IS NULL THEN
-- Create both current and open lots
INSERT INTO stock_lot (product_id, lot_number, status)
VALUES (prod_record.id, 'OTC-INIT-' || prod_record.id, 'current')
RETURNING id INTO current_lot_id;
INSERT INTO stock_lot (product_id, status)
VALUES (prod_record.id, 'open');
-- Add initial stock
INSERT INTO stock_move (product_id, lot_id, from_location_id, to_location_id, qty, move_type, note)
SELECT
prod_record.id,
current_lot_id,
NULL,
l.id,
100.0,
'in',
'Initial OTC stock'
FROM location l
WHERE l.type = 'storage'
ORDER BY l.id
LIMIT 1;
ELSE
-- Promote open lot to current
UPDATE stock_lot
SET status = 'current',
lot_number = COALESCE(lot_number, 'OTC-' || prod_record.id || '-' || open_lot_id),
updated_at = NOW()
WHERE id = open_lot_id;
-- Create new open lot
INSERT INTO stock_lot (product_id, status)
VALUES (prod_record.id, 'open');
END IF;
END IF;
END LOOP;
END $$;
COMMIT;