feat: cashier/counter reports, service-order & remission flows, Rached migration utils
- Add "Mis cortes de caja" report for cashiers/counters with sales detail. - Cash register history scoped to own cuts for non-admin roles; new /register/<id>/sales endpoint. - Remove dashboard from cashier menu; add Reports to cashier/counter. - Service orders: assign mechanic, budget field, invoice flag, counter/cashier can add items/remissions, convert to remission. - Remission notes module (UI, CSS, courier, counter remissions). - Customer hard-delete and vehicle/customer linkage in workshop. - POS: always show search results, compact payment grid, credit validation, tier pricing (5%/10%), ticket with customer/folio. - Inventory: CSV template with sku_secondary, alias import. - Rached migration scripts and DB migrations. - Version-bump cached JS/CSS query strings. Excludes local Rached session tokens/captures (rached_*.json / rached_*.txt).
This commit is contained in:
@@ -57,6 +57,19 @@ MIGRATIONS = {
|
||||
"v4.8": "v4.8_workshop_permissions.sql",
|
||||
"v4.9": "v4.9_workshop_customers_view.sql",
|
||||
"v4.10": "v4.10_fleet_permissions.sql",
|
||||
"v4.11": "v4.11_clean_workshop_mechanic_permissions.sql",
|
||||
"v4.12": "v4.12_service_order_soft_delete.sql",
|
||||
"v4.13": "v4.13_fleet_vehicle_customer.sql",
|
||||
"v4.14": "v4.14_service_order_delivery_cleanup.sql",
|
||||
"v4.15": "v4.15_counter_remission.sql",
|
||||
"v4.16": "v4.16_remission_courier.sql",
|
||||
"v4.17": "v4.17_service_order_invoice.sql",
|
||||
"v4.18": "v4.18_rached_workshop.sql",
|
||||
"v4.19": "v4.19_counter_inventory_create.sql",
|
||||
"v4.20": "v4.20_cashier_sell_permissions.sql",
|
||||
"v4.21": "v4.21_cashier_workshop_permissions.sql",
|
||||
"v4.22": "v4.22_cashier_invoicing_permissions.sql",
|
||||
"v4.23": "v4.23_service_order_mechanic_name.sql",
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +125,10 @@ def apply_migration(db_name, version):
|
||||
def run_migrations():
|
||||
"""Apply pending migrations to all tenants."""
|
||||
tenants = get_all_tenants()
|
||||
sorted_versions = sorted(MIGRATIONS.keys())
|
||||
def _version_key(v):
|
||||
return tuple(int(x) for x in v.lstrip('v').split('.'))
|
||||
|
||||
sorted_versions = sorted(MIGRATIONS.keys(), key=_version_key)
|
||||
|
||||
print(f"Found {len(tenants)} active tenants")
|
||||
print(f"Available migrations: {sorted_versions}")
|
||||
@@ -120,8 +136,9 @@ def run_migrations():
|
||||
for tenant_id, db_name, name, current_version in tenants:
|
||||
print(f"\n[{name}] (db={db_name}, current={current_version})")
|
||||
|
||||
current_key = _version_key(current_version)
|
||||
for version in sorted_versions:
|
||||
if version <= current_version:
|
||||
if _version_key(version) <= current_key:
|
||||
continue
|
||||
|
||||
print(f" Applying {version}...", end=" ")
|
||||
|
||||
10
pos/migrations/v4.14_service_order_delivery_cleanup.sql
Normal file
10
pos/migrations/v4.14_service_order_delivery_cleanup.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Normalize service order delivery options to only "pickup" (mostrador) and "delivery" (a domicilio).
|
||||
-- Convert legacy "courier" records to pickup and clear courier_id when delivery is not "delivery".
|
||||
|
||||
UPDATE service_orders
|
||||
SET delivery_method = 'pickup'
|
||||
WHERE delivery_method = 'courier';
|
||||
|
||||
UPDATE service_orders
|
||||
SET courier_id = NULL
|
||||
WHERE delivery_method IS NULL OR delivery_method != 'delivery';
|
||||
18
pos/migrations/v4.15_counter_remission.sql
Normal file
18
pos/migrations/v4.15_counter_remission.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
-- v4.15: Counter remission note support
|
||||
-- Ensures employees with role 'counter' have the base permissions needed to
|
||||
-- generate remission notes from the POS.
|
||||
|
||||
INSERT INTO employee_permissions (employee_id, permission)
|
||||
SELECT e.id, p.permission
|
||||
FROM employees e
|
||||
CROSS JOIN (
|
||||
VALUES
|
||||
('pos.remission'),
|
||||
('pos.view'),
|
||||
('catalog.view'),
|
||||
('inventory.view'),
|
||||
('customers.view'),
|
||||
('customers.create')
|
||||
) AS p(permission)
|
||||
WHERE e.role = 'counter'
|
||||
ON CONFLICT (employee_id, permission) DO NOTHING;
|
||||
18
pos/migrations/v4.16_remission_courier.sql
Normal file
18
pos/migrations/v4.16_remission_courier.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
-- v4.16: Add courier assignment to counter remission notes.
|
||||
|
||||
ALTER TABLE sales
|
||||
ADD COLUMN IF NOT EXISTS courier_id INTEGER;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint
|
||||
WHERE conname = 'sales_courier_id_fkey'
|
||||
) THEN
|
||||
ALTER TABLE sales
|
||||
ADD CONSTRAINT sales_courier_id_fkey
|
||||
FOREIGN KEY (courier_id) REFERENCES couriers(id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sales_courier_id ON sales(courier_id);
|
||||
6
pos/migrations/v4.17_service_order_invoice.sql
Normal file
6
pos/migrations/v4.17_service_order_invoice.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
-- Service order invoice requirement flag
|
||||
ALTER TABLE service_orders
|
||||
ADD COLUMN IF NOT EXISTS requires_invoice BOOLEAN DEFAULT FALSE;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_service_orders_requires_invoice
|
||||
ON service_orders(requires_invoice);
|
||||
32
pos/migrations/v4.18_rached_workshop.sql
Normal file
32
pos/migrations/v4.18_rached_workshop.sql
Normal file
@@ -0,0 +1,32 @@
|
||||
-- v4.18 Rached workshop fields
|
||||
-- Extends service orders and items to match the Rached legacy workshop flow.
|
||||
-- Applied to all tenants.
|
||||
|
||||
-- ═════════════════════════════════════════════════════════════════════════════
|
||||
-- 1. SERVICE_ORDERS: capture free-text customer/vehicle/workshop data
|
||||
-- ═════════════════════════════════════════════════════════════════════════════
|
||||
ALTER TABLE service_orders
|
||||
ADD COLUMN IF NOT EXISTS workshop_name VARCHAR(200),
|
||||
ADD COLUMN IF NOT EXISTS customer_address TEXT,
|
||||
ADD COLUMN IF NOT EXISTS customer_phone VARCHAR(50),
|
||||
ADD COLUMN IF NOT EXISTS vehicle_description VARCHAR(300);
|
||||
|
||||
COMMENT ON COLUMN service_orders.workshop_name IS 'Free-text workshop/customer alias (Rached "Taller")';
|
||||
COMMENT ON COLUMN service_orders.customer_address IS 'Address captured or imported for the service order';
|
||||
COMMENT ON COLUMN service_orders.customer_phone IS 'Phone captured or imported for the service order';
|
||||
COMMENT ON COLUMN service_orders.vehicle_description IS 'Free-text vehicle description (alternative to fleet_vehicles)';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_service_orders_workshop_name ON service_orders(workshop_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_service_orders_vehicle_description ON service_orders(vehicle_description);
|
||||
|
||||
-- ═════════════════════════════════════════════════════════════════════════════
|
||||
-- 2. SERVICE_ORDER_ITEMS: mechanic per item + explicit observations
|
||||
-- ═════════════════════════════════════════════════════════════════════════════
|
||||
ALTER TABLE service_order_items
|
||||
ADD COLUMN IF NOT EXISTS mechanic_id INTEGER REFERENCES employees(id),
|
||||
ADD COLUMN IF NOT EXISTS observations TEXT;
|
||||
|
||||
COMMENT ON COLUMN service_order_items.mechanic_id IS 'Mechanic assigned to this specific line item';
|
||||
COMMENT ON COLUMN service_order_items.observations IS 'Line-item observations (Rached detail notes)';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_service_order_items_mechanic_id ON service_order_items(mechanic_id);
|
||||
11
pos/migrations/v4.19_counter_inventory_create.sql
Normal file
11
pos/migrations/v4.19_counter_inventory_create.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- v4.19 — Grant inventory.create permission to existing counter employees
|
||||
-- so they can create items and record purchase entries.
|
||||
INSERT INTO employee_permissions (employee_id, permission)
|
||||
SELECT e.id, 'inventory.create'
|
||||
FROM employees e
|
||||
WHERE e.role = 'counter'
|
||||
AND e.is_active = true
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM employee_permissions ep
|
||||
WHERE ep.employee_id = e.id AND ep.permission = 'inventory.create'
|
||||
);
|
||||
18
pos/migrations/v4.20_cashier_sell_permissions.sql
Normal file
18
pos/migrations/v4.20_cashier_sell_permissions.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
-- v4.20 — Ensure existing cashier employees can sell and view quotations.
|
||||
-- The cashier default set already includes these permissions, but employees
|
||||
-- created before the fix may be missing them.
|
||||
INSERT INTO employee_permissions (employee_id, permission)
|
||||
SELECT e.id, p.perm
|
||||
FROM employees e
|
||||
CROSS JOIN (VALUES
|
||||
('pos.sell'),
|
||||
('pos.discount'),
|
||||
('pos.cancel'),
|
||||
('pos.view')
|
||||
) AS p(perm)
|
||||
WHERE e.role = 'cashier'
|
||||
AND e.is_active = true
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM employee_permissions ep
|
||||
WHERE ep.employee_id = e.id AND ep.permission = p.perm
|
||||
);
|
||||
15
pos/migrations/v4.21_cashier_workshop_permissions.sql
Normal file
15
pos/migrations/v4.21_cashier_workshop_permissions.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- v4.21 — Allow existing cashier employees to create and edit service orders.
|
||||
INSERT INTO employee_permissions (employee_id, permission)
|
||||
SELECT e.id, p.perm
|
||||
FROM employees e
|
||||
CROSS JOIN (VALUES
|
||||
('workshop.view'),
|
||||
('workshop.edit'),
|
||||
('workshop.add_items')
|
||||
) AS p(perm)
|
||||
WHERE e.role = 'cashier'
|
||||
AND e.is_active = true
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM employee_permissions ep
|
||||
WHERE ep.employee_id = e.id AND ep.permission = p.perm
|
||||
);
|
||||
15
pos/migrations/v4.22_cashier_invoicing_permissions.sql
Normal file
15
pos/migrations/v4.22_cashier_invoicing_permissions.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- v4.22 -- Enable invoicing for existing cashier employees.
|
||||
INSERT INTO employee_permissions (employee_id, permission)
|
||||
SELECT e.id, p.perm
|
||||
FROM employees e
|
||||
CROSS JOIN (VALUES
|
||||
('invoicing.view'),
|
||||
('invoicing.create'),
|
||||
('invoicing.cancel')
|
||||
) AS p(perm)
|
||||
WHERE e.role = 'cashier'
|
||||
AND e.is_active = true
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM employee_permissions ep
|
||||
WHERE ep.employee_id = e.id AND ep.permission = p.perm
|
||||
);
|
||||
2
pos/migrations/v4.23_service_order_mechanic_name.sql
Normal file
2
pos/migrations/v4.23_service_order_mechanic_name.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- v4.23 -- Add free-text mechanic name for service orders.
|
||||
ALTER TABLE service_orders ADD COLUMN IF NOT EXISTS mechanic_name TEXT;
|
||||
Reference in New Issue
Block a user