Autosave: 20260216-122213
This commit is contained in:
parent
a4b8ae74c2
commit
c826515451
@ -69,6 +69,116 @@ body {
|
||||
font-weight: 600;
|
||||
color: #64748b !important;
|
||||
letter-spacing: 0.05em;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-section-title:hover {
|
||||
color: #94a3b8 !important;
|
||||
}
|
||||
|
||||
.nav-section-title i.bi-chevron-down {
|
||||
transition: transform 0.2s;
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.nav-section-title.collapsed i.bi-chevron-down {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
/* POS Styles */
|
||||
.pos-container {
|
||||
display: flex;
|
||||
height: calc(100vh - 120px);
|
||||
gap: 20px;
|
||||
}
|
||||
.pos-products {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.pos-cart {
|
||||
width: 400px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
.product-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
.product-card {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #edf2f7;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.product-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
.product-card img {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
object-fit: contain;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.product-card .price {
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
}
|
||||
.cart-items {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.cart-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #edf2f7;
|
||||
}
|
||||
.cart-total {
|
||||
padding: 20px;
|
||||
background: #f8fafc;
|
||||
border-bottom-left-radius: 12px;
|
||||
border-bottom-right-radius: 12px;
|
||||
}
|
||||
.qty-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.qty-btn {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #e2e8f0;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
.qty-btn:hover {
|
||||
background: #edf2f7;
|
||||
}
|
||||
|
||||
[dir="rtl"] .nav-link i {
|
||||
@ -138,3 +248,58 @@ body {
|
||||
[dir="rtl"] .text-start {
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
/* Thermal Receipt Styles */
|
||||
.thermal-receipt {
|
||||
width: 80mm;
|
||||
margin: 0 auto;
|
||||
padding: 10px;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
.thermal-receipt .center {
|
||||
text-align: center;
|
||||
}
|
||||
.thermal-receipt .separator {
|
||||
border-top: 1px dashed #000;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.thermal-receipt table {
|
||||
width: 100%;
|
||||
}
|
||||
.thermal-receipt table th {
|
||||
text-align: left;
|
||||
border-bottom: 1px dashed #000;
|
||||
font-size: 10px;
|
||||
}
|
||||
.thermal-receipt table td {
|
||||
padding: 5px 0;
|
||||
font-size: 10px;
|
||||
}
|
||||
.thermal-receipt .total-row {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.thermal-receipt-print {
|
||||
width: 80mm !important;
|
||||
margin: 0 !important;
|
||||
padding: 5mm !important;
|
||||
}
|
||||
body.printing-receipt * {
|
||||
visibility: hidden;
|
||||
}
|
||||
body.printing-receipt .thermal-receipt-print,
|
||||
body.printing-receipt .thermal-receipt-print * {
|
||||
visibility: visible;
|
||||
}
|
||||
body.printing-receipt .thermal-receipt-print {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
44
db/migrations/20260216_pos_advanced_features.sql
Normal file
44
db/migrations/20260216_pos_advanced_features.sql
Normal file
@ -0,0 +1,44 @@
|
||||
-- Held Carts Table
|
||||
CREATE TABLE IF NOT EXISTS pos_held_carts (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
cart_name VARCHAR(100) NOT NULL,
|
||||
items_json TEXT NOT NULL,
|
||||
customer_id INT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- Discount Codes Table
|
||||
CREATE TABLE IF NOT EXISTS discount_codes (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
code VARCHAR(50) UNIQUE NOT NULL,
|
||||
type ENUM('percentage', 'fixed') NOT NULL DEFAULT 'percentage',
|
||||
value DECIMAL(15, 3) NOT NULL,
|
||||
min_purchase DECIMAL(15, 3) DEFAULT 0.000,
|
||||
expiry_date DATE NULL,
|
||||
status ENUM('active', 'inactive') DEFAULT 'active',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Update Customers for Loyalty Points
|
||||
-- Check if column exists first (handled by IF NOT EXISTS in some dialects, but let's be safe for MySQL 5.7/MariaDB)
|
||||
-- Using a procedure or just trying it. MySQL 8.0/MariaDB supports IF NOT EXISTS for ADD COLUMN but older versions don't always.
|
||||
-- For this VM, we can just run it.
|
||||
|
||||
ALTER TABLE customers ADD COLUMN IF NOT EXISTS loyalty_points DECIMAL(15, 3) DEFAULT 0.000;
|
||||
|
||||
-- Update POS Transactions for Discounts and Loyalty
|
||||
ALTER TABLE pos_transactions
|
||||
ADD COLUMN IF NOT EXISTS discount_code_id INT NULL,
|
||||
ADD COLUMN IF NOT EXISTS discount_amount DECIMAL(15, 3) DEFAULT 0.000,
|
||||
ADD COLUMN IF NOT EXISTS loyalty_points_earned DECIMAL(15, 3) DEFAULT 0.000,
|
||||
ADD COLUMN IF NOT EXISTS loyalty_points_redeemed DECIMAL(15, 3) DEFAULT 0.000,
|
||||
ADD COLUMN IF NOT EXISTS net_amount DECIMAL(15, 3) NOT NULL DEFAULT 0.000;
|
||||
|
||||
-- Adding foreign key separately to be safe
|
||||
-- ALTER TABLE pos_transactions ADD FOREIGN KEY (discount_code_id) REFERENCES discount_codes(id) ON DELETE SET NULL;
|
||||
|
||||
-- Insert some dummy discount codes
|
||||
INSERT IGNORE INTO discount_codes (code, type, value, min_purchase) VALUES
|
||||
('WELCOME10', 'percentage', 10.000, 0.000),
|
||||
('SAVE5', 'fixed', 5.000, 50.000);
|
||||
57
db/migrations/20260216_setup_pos_full.sql
Normal file
57
db/migrations/20260216_setup_pos_full.sql
Normal file
@ -0,0 +1,57 @@
|
||||
-- Main POS Transactions Table
|
||||
CREATE TABLE IF NOT EXISTS pos_transactions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
transaction_no VARCHAR(50) UNIQUE NOT NULL,
|
||||
customer_id INT NULL,
|
||||
total_amount DECIMAL(15, 3) NOT NULL,
|
||||
tax_amount DECIMAL(15, 3) DEFAULT 0.000,
|
||||
discount_code_id INT NULL,
|
||||
discount_amount DECIMAL(15, 3) DEFAULT 0.000,
|
||||
loyalty_points_earned DECIMAL(15, 3) DEFAULT 0.000,
|
||||
loyalty_points_redeemed DECIMAL(15, 3) DEFAULT 0.000,
|
||||
net_amount DECIMAL(15, 3) NOT NULL DEFAULT 0.000,
|
||||
payment_method ENUM('cash', 'card', 'transfer') NOT NULL,
|
||||
status ENUM('completed', 'refunded', 'cancelled') DEFAULT 'completed',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by INT NULL
|
||||
);
|
||||
|
||||
-- POS Items Table
|
||||
CREATE TABLE IF NOT EXISTS pos_items (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
transaction_id INT NOT NULL,
|
||||
product_id INT NOT NULL,
|
||||
quantity DECIMAL(15, 3) NOT NULL,
|
||||
unit_price DECIMAL(15, 3) NOT NULL,
|
||||
subtotal DECIMAL(15, 3) NOT NULL,
|
||||
FOREIGN KEY (transaction_id) REFERENCES pos_transactions(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Held Carts Table
|
||||
CREATE TABLE IF NOT EXISTS pos_held_carts (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
cart_name VARCHAR(100) NOT NULL,
|
||||
items_json TEXT NOT NULL,
|
||||
customer_id INT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Discount Codes Table
|
||||
CREATE TABLE IF NOT EXISTS discount_codes (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
code VARCHAR(50) UNIQUE NOT NULL,
|
||||
type ENUM('percentage', 'fixed') NOT NULL DEFAULT 'percentage',
|
||||
value DECIMAL(15, 3) NOT NULL,
|
||||
min_purchase DECIMAL(15, 3) DEFAULT 0.000,
|
||||
expiry_date DATE NULL,
|
||||
status ENUM('active', 'inactive') DEFAULT 'active',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Add Loyalty Points to Customers if missing
|
||||
ALTER TABLE customers ADD COLUMN IF NOT EXISTS loyalty_points DECIMAL(15, 3) DEFAULT 0.000;
|
||||
|
||||
-- Insert initial discount codes
|
||||
INSERT IGNORE INTO discount_codes (code, type, value, min_purchase) VALUES
|
||||
('WELCOME10', 'percentage', 10.000, 0.000),
|
||||
('SAVE5', 'fixed', 5.000, 50.000);
|
||||
Loading…
x
Reference in New Issue
Block a user