Revamp Done - Support for Individual and Jwellery module added

This commit is contained in:
2026-08-29 12:01:00 +05:30
parent eacca6aaea
commit cdc58c9bce
37 changed files with 4334 additions and 2935 deletions

View File

@@ -34,6 +34,7 @@ public class ProductCategoryController {
public Mono<ResponseEntity<ProductCategory>> createCategory(Authentication authentication, @RequestBody ProductCategory category) {
Long userId = Long.valueOf(authentication.getDetails().toString());
category.setUserId(userId);
category.setPurityFactor(normalizePurity(category.getPurityFactor()));
category.setCreatedAt(LocalDateTime.now());
return categoryRepository.save(category)
.map(ResponseEntity::ok);
@@ -47,7 +48,7 @@ public class ProductCategoryController {
existing.setParentCategoryId(category.getParentCategoryId());
existing.setHasChild(category.getHasChild());
existing.setCommodityCode(category.getCommodityCode());
existing.setPurityFactor(category.getPurityFactor() != null ? category.getPurityFactor() : 1.0);
existing.setPurityFactor(normalizePurity(category.getPurityFactor()));
existing.setDefaultHsn(category.getDefaultHsn());
existing.setDefaultGst(category.getDefaultGst());
existing.setHuidRequired(category.getHuidRequired());
@@ -63,4 +64,12 @@ public class ProductCategoryController {
.defaultIfEmpty(ResponseEntity.notFound().build());
}
private Double normalizePurity(Double rawPurity) {
if (rawPurity == null || rawPurity <= 0) return 1.0;
double p = rawPurity;
if (p > 1.0) p = p / 100.0;
if (p > 1.0) p = 1.0;
return p;
}
}

View File

@@ -43,6 +43,15 @@ public class Invoice {
@Column("tax_total")
private BigDecimal taxTotal;
@Column("cgst_total")
private BigDecimal cgstTotal;
@Column("sgst_total")
private BigDecimal sgstTotal;
@Column("igst_total")
private BigDecimal igstTotal;
@Column("discount_total")
private BigDecimal discountTotal;

View File

@@ -46,8 +46,20 @@ public class InvoiceItem {
@Column("making_charge")
private BigDecimal makingCharge;
@Column("making_charges_type")
private String makingChargesType;
@Column("other_charges")
private BigDecimal otherCharges;
private String huid;
private BigDecimal weight;
private BigDecimal cgst;
private BigDecimal sgst;
private BigDecimal igst;
@Column("photo_url")
private String photoUrl;
private BigDecimal total;
}

View File

@@ -28,6 +28,8 @@ public class SetupService {
public Mono<java.util.Map<String, String>> getSetupStatus(Long userId) {
return userRepository.findById(userId)
.switchIfEmpty(Mono.error(new org.springframework.web.server.ResponseStatusException(
org.springframework.http.HttpStatus.UNAUTHORIZED, "User does not exist")))
.map(u -> {
java.util.Map<String, String> map = new java.util.HashMap<>();
map.put("status", u.getSetupStatus() != null ? u.getSetupStatus() : "NOT_STARTED");
@@ -35,8 +37,7 @@ public class SetupService {
map.put("name", u.getName() != null ? u.getName() : "");
map.put("email", u.getEmail() != null ? u.getEmail() : "");
return map;
})
.defaultIfEmpty(java.util.Map.of("status", "NOT_STARTED", "profileType", "INDIVIDUAL"));
});
}
public Mono<Boolean> isUsernameAvailable(String username) {

View File

@@ -54,10 +54,10 @@ public class CommodityRateService {
.flatMap(latestRate ->
productCategoryRepository.findByUserIdAndCommodityCode(userId, commodityCode)
.flatMap(category -> {
double categoryPurity = category.getPurityFactor() != null ? category.getPurityFactor() : 1.0;
final double categoryPurity = normalizePurity(category.getPurityFactor());
return productRepository.findByCategoryId(category.getId())
.flatMap(product -> {
double productPurity = product.getPurityFactor() != null ? product.getPurityFactor() : categoryPurity;
double productPurity = normalizePurity(product.getPurityFactor() != null ? product.getPurityFactor() : categoryPurity);
BigDecimal baseRate = latestRate.getRate().multiply(BigDecimal.valueOf(productPurity));
if ("WEIGHT_BASED".equalsIgnoreCase(product.getPriceCalcRule())) {
@@ -79,4 +79,12 @@ public class CommodityRateService {
)
.defaultIfEmpty(0);
}
private Double normalizePurity(Double rawPurity) {
if (rawPurity == null || rawPurity <= 0) return 1.0;
double p = rawPurity;
if (p > 1.0) p = p / 100.0;
if (p > 1.0) p = 1.0;
return p;
}
}

View File

@@ -68,7 +68,9 @@ public class ProductService {
product.setUpdatedAt(LocalDateTime.now());
if (product.getIsActive() == null) product.setIsActive(true);
if (product.getPriceCalcRule() == null) product.setPriceCalcRule("MANUAL");
if (product.getPurityFactor() == null) product.setPurityFactor(1.0);
product.setPurityFactor(normalizePurity(product.getPurityFactor()));
if (product.getMakingCharges() == null) product.setMakingCharges(0.0);
if (product.getMakingChargesType() == null) product.setMakingChargesType("PER_GRAM");
return productRepository.save(product);
}
@@ -87,7 +89,7 @@ public class ProductService {
existingProduct.setSize(updatedProduct.getSize());
existingProduct.setDimensions(updatedProduct.getDimensions());
existingProduct.setPriceCalcRule(updatedProduct.getPriceCalcRule());
existingProduct.setPurityFactor(updatedProduct.getPurityFactor());
existingProduct.setPurityFactor(normalizePurity(updatedProduct.getPurityFactor()));
existingProduct.setMakingCharges(updatedProduct.getMakingCharges());
existingProduct.setMakingChargesType(updatedProduct.getMakingChargesType());
existingProduct.setWastagePercentage(updatedProduct.getWastagePercentage());
@@ -288,4 +290,13 @@ public class ProductService {
.switchIfEmpty(Mono.error(new RuntimeException("Access denied")))
.flatMap(p -> productBomRepository.delete(bom)));
}
private Double normalizePurity(Double rawPurity) {
if (rawPurity == null) return null;
if (rawPurity <= 0) return 1.0;
double p = rawPurity;
if (p > 1.0) p = p / 100.0;
if (p > 1.0) p = 1.0;
return p;
}
}

View File

@@ -1,169 +1,43 @@
-- ==========================================================
-- KIFI PLATFORM CONSOLIDATED DATABASE SCHEMA
-- ==========================================================
-- 1. Core Users Table
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255),
username VARCHAR(255) UNIQUE,
name VARCHAR(255),
mobile_number VARCHAR(255),
profile_type VARCHAR(20) DEFAULT 'INDIVIDUAL',
setup_status VARCHAR(50) DEFAULT 'NOT_STARTED',
setup_completed_at TIMESTAMP,
enabled BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS merchants (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
name VARCHAR(255) NOT NULL,
icon_name VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS categories (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
name VARCHAR(255) NOT NULL,
icon_name VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS transactions (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
category_id INTEGER REFERENCES categories(id),
type VARCHAR(50) NOT NULL, -- 'INCOME' or 'EXPENSE' or 'INVESTMENT'
amount DECIMAL(10, 2) NOT NULL,
date DATE NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS budgets (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
category_id INTEGER REFERENCES categories(id),
monthly_limit DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, category_id)
);
CREATE TABLE IF NOT EXISTS recurring_transactions (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
category_id INTEGER REFERENCES categories(id),
type VARCHAR(50) NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
frequency VARCHAR(50) NOT NULL,
next_execution_date DATE NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS wallets (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
owner_id INTEGER REFERENCES users(id),
nature VARCHAR(50) DEFAULT 'CASH', -- 'CASH', 'DEPOSIT', 'EXPENSE', 'INCOME', 'SAVINGS', 'LOAN', etc.
balance DECIMAL(15, 2) DEFAULT 0.00,
currency VARCHAR(10) DEFAULT 'INR',
icon VARCHAR(255),
color VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS user_wallets (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
wallet_id INTEGER REFERENCES wallets(id),
role VARCHAR(50) DEFAULT 'MEMBER',
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE (user_id, wallet_id)
);
ALTER TABLE wallets ADD COLUMN IF NOT EXISTS nature VARCHAR(50) DEFAULT 'CASH';
ALTER TABLE wallets ADD COLUMN IF NOT EXISTS balance DECIMAL(15, 2) DEFAULT 0.00;
ALTER TABLE wallets ADD COLUMN IF NOT EXISTS currency VARCHAR(10) DEFAULT 'INR';
ALTER TABLE wallets ADD COLUMN IF NOT EXISTS icon VARCHAR(255);
ALTER TABLE wallets ADD COLUMN IF NOT EXISTS color VARCHAR(50);
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS wallet_id INTEGER REFERENCES wallets(id);
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS from_wallet_id INTEGER REFERENCES wallets(id);
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS to_wallet_id INTEGER REFERENCES wallets(id);
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS notes TEXT;
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS due_date DATE;
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS alert_schedule VARCHAR(50);
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS alert_time TIME;
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS investment_status VARCHAR(20) DEFAULT 'OPEN';
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS maturity_amount DECIMAL(10, 2);
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS profit_loss DECIMAL(10, 2);
ALTER TABLE transactions ADD COLUMN IF NOT EXISTS closing_date DATE;
CREATE TABLE IF NOT EXISTS transaction_items (
id SERIAL PRIMARY KEY,
transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS transaction_attachments (
id SERIAL PRIMARY KEY,
transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE,
file_name VARCHAR(255) NOT NULL,
file_path VARCHAR(1024) NOT NULL,
content_type VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
ALTER TABLE budgets ADD COLUMN IF NOT EXISTS wallet_id INTEGER REFERENCES wallets(id);
ALTER TABLE budgets ADD COLUMN IF NOT EXISTS is_shared BOOLEAN DEFAULT FALSE;
-- Ensure budget can be either category-specific or wallet-specific
ALTER TABLE budgets ALTER COLUMN category_id DROP NOT NULL;
ALTER TABLE recurring_transactions ADD COLUMN IF NOT EXISTS from_wallet_id INTEGER REFERENCES wallets(id);
ALTER TABLE recurring_transactions ADD COLUMN IF NOT EXISTS to_wallet_id INTEGER REFERENCES wallets(id);
ALTER TABLE recurring_transactions ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'ACTIVE';
ALTER TABLE recurring_transactions ADD COLUMN IF NOT EXISTS end_date DATE;
ALTER TABLE recurring_transactions ALTER COLUMN category_id DROP NOT NULL;
CREATE TABLE IF NOT EXISTS wallet_invitations (
id SERIAL PRIMARY KEY,
wallet_id INTEGER REFERENCES wallets(id),
inviter_id INTEGER REFERENCES users(id),
invitee_email VARCHAR(255) NOT NULL,
status VARCHAR(20) DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- KIFI V2 PHASE 1 MIGRATION: INVENTORY MANAGEMENT --
ALTER TABLE users ADD COLUMN IF NOT EXISTS profile_type VARCHAR(20) DEFAULT 'INDIVIDUAL';
CREATE TABLE IF NOT EXISTS business_profiles (
-- 2. User Consents
CREATE TABLE IF NOT EXISTS user_consents (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
business_name VARCHAR(255) NOT NULL,
industry VARCHAR(100),
tax_number VARCHAR(100),
currency VARCHAR(10) DEFAULT 'INR',
tax_included_in_price BOOLEAN DEFAULT FALSE,
address TEXT,
state_id INTEGER,
contact_person VARCHAR(100),
contact_number VARCHAR(20),
email_id VARCHAR(100),
pan_number VARCHAR(255),
gstin VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id)
consent_type VARCHAR(100) NOT NULL,
policy_version VARCHAR(50) NOT NULL,
accepted BOOLEAN DEFAULT TRUE,
accepted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR(100),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 3. Business Profiles & Features
CREATE TABLE IF NOT EXISTS indian_states (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
gst_code VARCHAR(2) NOT NULL
);
-- Seed Indian States if empty
INSERT INTO indian_states (name, gst_code) VALUES
('Jammu & Kashmir', '01'), ('Himachal Pradesh', '02'), ('Punjab', '03'),
('Chandigarh', '04'), ('Uttarakhand', '05'), ('Haryana', '06'),
@@ -180,6 +54,28 @@ INSERT INTO indian_states (name, gst_code) VALUES
('Telangana', '36'), ('Andhra Pradesh', '37'), ('Ladakh', '38')
ON CONFLICT DO NOTHING;
CREATE TABLE IF NOT EXISTS business_profiles (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
business_name VARCHAR(255) NOT NULL,
industry VARCHAR(100),
tax_number VARCHAR(100),
currency VARCHAR(10) DEFAULT 'INR',
tax_included_in_price BOOLEAN DEFAULT FALSE,
address TEXT,
state_id INTEGER REFERENCES indian_states(id),
contact_person VARCHAR(100),
contact_number VARCHAR(20),
email_id VARCHAR(100),
pan_number VARCHAR(255),
gstin VARCHAR(255),
nature_of_business VARCHAR(50),
msme_number VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id)
);
CREATE TABLE IF NOT EXISTS business_features (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
@@ -187,20 +83,128 @@ CREATE TABLE IF NOT EXISTS business_features (
sales_management BOOLEAN DEFAULT FALSE,
multi_location BOOLEAN DEFAULT FALSE,
bom_reduction_strategy VARCHAR(50) DEFAULT 'COMPONENTS_ONLY',
stock_deduction_on_invoice BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id)
);
-- 4. Personal Finance: Wallets, Categories, Transactions & Budgets
CREATE TABLE IF NOT EXISTS wallets (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
owner_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
nature VARCHAR(50) DEFAULT 'CASH', -- 'CASH', 'DEPOSIT', 'EXPENSE', 'INCOME', 'SAVINGS', 'LOAN', etc.
balance DECIMAL(15, 2) DEFAULT 0.00,
currency VARCHAR(10) DEFAULT 'INR',
icon VARCHAR(255),
color VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS user_wallets (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
wallet_id INTEGER REFERENCES wallets(id) ON DELETE CASCADE,
role VARCHAR(50) DEFAULT 'MEMBER',
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE (user_id, wallet_id)
);
CREATE TABLE IF NOT EXISTS wallet_invitations (
id SERIAL PRIMARY KEY,
wallet_id INTEGER REFERENCES wallets(id) ON DELETE CASCADE,
inviter_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
invitee_email VARCHAR(255) NOT NULL,
status VARCHAR(20) DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS categories (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
icon_name VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS transactions (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
wallet_id INTEGER REFERENCES wallets(id) ON DELETE SET NULL,
from_wallet_id INTEGER REFERENCES wallets(id) ON DELETE SET NULL,
to_wallet_id INTEGER REFERENCES wallets(id) ON DELETE SET NULL,
type VARCHAR(50) NOT NULL, -- 'INCOME', 'EXPENSE', 'INVESTMENT', 'TRANSFER'
amount DECIMAL(15, 2) NOT NULL,
date DATE NOT NULL,
description TEXT,
notes TEXT,
due_date DATE,
alert_schedule VARCHAR(50),
alert_time TIME,
investment_status VARCHAR(20) DEFAULT 'OPEN',
maturity_amount DECIMAL(15, 2),
profit_loss DECIMAL(15, 2),
closing_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS transaction_items (
id SERIAL PRIMARY KEY,
transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
amount DECIMAL(15, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS transaction_attachments (
id SERIAL PRIMARY KEY,
transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE,
file_name VARCHAR(255) NOT NULL,
file_path VARCHAR(1024) NOT NULL,
content_type VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS budgets (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
wallet_id INTEGER REFERENCES wallets(id) ON DELETE SET NULL,
is_shared BOOLEAN DEFAULT FALSE,
monthly_limit DECIMAL(15, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, category_id)
);
CREATE TABLE IF NOT EXISTS recurring_transactions (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
from_wallet_id INTEGER REFERENCES wallets(id) ON DELETE SET NULL,
to_wallet_id INTEGER REFERENCES wallets(id) ON DELETE SET NULL,
type VARCHAR(50) NOT NULL,
amount DECIMAL(15, 2) NOT NULL,
frequency VARCHAR(50) NOT NULL,
next_execution_date DATE NOT NULL,
end_date DATE,
status VARCHAR(20) DEFAULT 'ACTIVE',
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 5. Inventory: Categories, Rates, Products, BOM, Locations
CREATE TABLE IF NOT EXISTS product_categories (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
parent_category_id INTEGER REFERENCES product_categories(id),
parent_category_id INTEGER REFERENCES product_categories(id) ON DELETE CASCADE,
has_child BOOLEAN DEFAULT FALSE,
default_hsn VARCHAR(50),
default_gst DECIMAL(5, 2),
huid_required BOOLEAN DEFAULT FALSE,
default_making_charge DECIMAL(15, 2),
making_charge_type VARCHAR(50),
commodity_code VARCHAR(10),
purity_factor DECIMAL(5, 4) DEFAULT 1.0,
base_unit VARCHAR(20) DEFAULT 'pcs',
@@ -217,38 +221,10 @@ CREATE TABLE IF NOT EXISTS commodity_rate_history (
rate DECIMAL(15, 2) NOT NULL,
effective_at TIMESTAMP NOT NULL,
source VARCHAR(100),
created_by INTEGER REFERENCES users(id),
created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS inventory_items (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
product_id INTEGER REFERENCES products(id),
tag_number VARCHAR(100),
sku VARCHAR(100),
huid VARCHAR(50),
purity VARCHAR(50),
gross_weight DECIMAL(10, 3),
net_weight DECIMAL(10, 3),
stone_weight DECIMAL(10, 3),
diamond_weight DECIMAL(10, 3),
fine_weight DECIMAL(10, 3),
making_charges DECIMAL(15, 2),
making_charge_type VARCHAR(50),
purchase_cost DECIMAL(15, 2),
metal_cost DECIMAL(15, 2),
stone_cost DECIMAL(15, 2),
certification_cost DECIMAL(15, 2),
tax DECIMAL(15, 2),
vendor_id INTEGER, -- REFERENCES vendors(id)
branch_id INTEGER,
purchase_ref VARCHAR(100),
status VARCHAR(50) DEFAULT 'AVAILABLE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS units_of_measure (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
@@ -260,8 +236,8 @@ CREATE TABLE IF NOT EXISTS units_of_measure (
CREATE TABLE IF NOT EXISTS products (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
category_id INTEGER REFERENCES product_categories(id),
uom_id INTEGER REFERENCES units_of_measure(id),
category_id INTEGER REFERENCES product_categories(id) ON DELETE SET NULL,
uom_id INTEGER REFERENCES units_of_measure(id) ON DELETE SET NULL,
name VARCHAR(255) NOT NULL,
sku VARCHAR(100),
barcode VARCHAR(100),
@@ -274,9 +250,9 @@ CREATE TABLE IF NOT EXISTS products (
color VARCHAR(50),
size VARCHAR(50),
price_calc_rule VARCHAR(50) DEFAULT 'MANUAL',
purity_factor DECIMAL(5, 4) DEFAULT 1.0,
purity_factor DECIMAL(5, 4),
making_charges DECIMAL(15, 2) DEFAULT 0.0,
making_charges_type VARCHAR(50) DEFAULT 'FLAT',
making_charges_type VARCHAR(50) DEFAULT 'PER_GRAM',
wastage_percentage DECIMAL(5, 2) DEFAULT 0.0,
min_stock DECIMAL(10, 2) DEFAULT 0,
reorder_level DECIMAL(10, 2) DEFAULT 0,
@@ -312,12 +288,112 @@ CREATE TABLE IF NOT EXISTS inventory_locations (
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 6. Vendors & Purchase Orders
CREATE TABLE IF NOT EXISTS vendors (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
email VARCHAR(255),
phone VARCHAR(50),
address TEXT,
gstin VARCHAR(50),
state_id INTEGER REFERENCES indian_states(id),
id_number VARCHAR(100),
photo_url VARCHAR(1024),
contact_person VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS purchase_orders (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
vendor_id INTEGER REFERENCES vendors(id) ON DELETE SET NULL,
po_number VARCHAR(100) NOT NULL,
issue_date DATE NOT NULL,
po_date DATE,
due_date DATE,
subtotal DECIMAL(15, 2) NOT NULL,
tax_total DECIMAL(15, 2) DEFAULT 0.0,
cgst_total DECIMAL(15, 2) DEFAULT 0.0,
sgst_total DECIMAL(15, 2) DEFAULT 0.0,
igst_total DECIMAL(15, 2) DEFAULT 0.0,
discount_total DECIMAL(15, 2) DEFAULT 0.0,
total_amount DECIMAL(15, 2) NOT NULL,
amount_paid DECIMAL(15, 2) DEFAULT 0.0,
next_payment_date DATE,
status VARCHAR(50) DEFAULT 'DRAFT',
notes TEXT,
vendor_invoice_url VARCHAR(1024),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS purchase_order_items (
id SERIAL PRIMARY KEY,
po_id INTEGER REFERENCES purchase_orders(id) ON DELETE CASCADE,
product_id INTEGER REFERENCES products(id) ON DELETE SET NULL,
quantity DECIMAL(10, 3) NOT NULL,
unit_price DECIMAL(15, 2) NOT NULL,
tax_rate DECIMAL(5, 2) DEFAULT 0.0,
cgst_rate DECIMAL(5, 2) DEFAULT 0.0,
sgst_rate DECIMAL(5, 2) DEFAULT 0.0,
igst_rate DECIMAL(5, 2) DEFAULT 0.0,
discount DECIMAL(15, 2) DEFAULT 0.0,
making_charge DECIMAL(15, 2) DEFAULT 0.0,
other_charges DECIMAL(15, 2) DEFAULT 0.0,
sku VARCHAR(100),
huid VARCHAR(50),
weight DECIMAL(10, 3),
photo_url VARCHAR(1024),
description VARCHAR(255),
total DECIMAL(15, 2) NOT NULL
);
CREATE TABLE IF NOT EXISTS purchase_payments (
id SERIAL PRIMARY KEY,
po_id INTEGER REFERENCES purchase_orders(id) ON DELETE CASCADE,
transaction_id INTEGER REFERENCES transactions(id) ON DELETE SET NULL,
amount DECIMAL(15, 2) NOT NULL,
payment_method VARCHAR(50),
payment_date TIMESTAMP NOT NULL,
notes TEXT
);
-- 7. Individual Stock Inventory Items
CREATE TABLE IF NOT EXISTS inventory_items (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
product_id INTEGER REFERENCES products(id) ON DELETE SET NULL,
tag_number VARCHAR(100),
sku VARCHAR(100),
huid VARCHAR(50),
purity VARCHAR(50),
gross_weight DECIMAL(10, 3),
net_weight DECIMAL(10, 3),
stone_weight DECIMAL(10, 3),
diamond_weight DECIMAL(10, 3),
fine_weight DECIMAL(10, 3),
making_charges DECIMAL(15, 2),
making_charge_type VARCHAR(50),
purchase_cost DECIMAL(15, 2),
metal_cost DECIMAL(15, 2),
stone_cost DECIMAL(15, 2),
certification_cost DECIMAL(15, 2),
tax DECIMAL(15, 2),
vendor_id INTEGER REFERENCES vendors(id) ON DELETE SET NULL,
branch_id INTEGER,
purchase_ref VARCHAR(100),
status VARCHAR(50) DEFAULT 'AVAILABLE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS inventory_movements (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
location_id INTEGER REFERENCES inventory_locations(id),
type VARCHAR(50) NOT NULL, -- ADDITION, REDUCTION, TRANSFER, ADJUSTMENT
reference_transaction_id INTEGER REFERENCES transactions(id),
location_id INTEGER REFERENCES inventory_locations(id) ON DELETE SET NULL,
type VARCHAR(50) NOT NULL,
reference_transaction_id INTEGER REFERENCES transactions(id) ON DELETE SET NULL,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
@@ -325,7 +401,7 @@ CREATE TABLE IF NOT EXISTS inventory_movements (
CREATE TABLE IF NOT EXISTS inventory_movement_items (
id SERIAL PRIMARY KEY,
movement_id INTEGER REFERENCES inventory_movements(id) ON DELETE CASCADE,
product_id INTEGER REFERENCES products(id),
product_id INTEGER REFERENCES products(id) ON DELETE SET NULL,
quantity DECIMAL(10, 2) NOT NULL,
unit_price DECIMAL(10, 2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
@@ -340,9 +416,7 @@ CREATE TABLE IF NOT EXISTS inventory_balances (
UNIQUE(product_id, location_id)
);
-- SALES & INVOICES (Phase 2)
ALTER TABLE business_features ADD COLUMN IF NOT EXISTS stock_deduction_on_invoice BOOLEAN DEFAULT TRUE;
-- 8. Customers, Sales & Invoices
CREATE TABLE IF NOT EXISTS customers (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
@@ -351,29 +425,27 @@ CREATE TABLE IF NOT EXISTS customers (
phone VARCHAR(50),
address TEXT,
gstin VARCHAR(50),
photo_url VARCHAR(1024),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS invoices (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
customer_id INTEGER REFERENCES customers(id),
customer_id INTEGER REFERENCES customers(id) ON DELETE SET NULL,
invoice_number VARCHAR(100) NOT NULL,
issue_date DATE NOT NULL,
due_date DATE,
subtotal DECIMAL(15,2) NOT NULL,
tax_total DECIMAL(15,2) DEFAULT 0.0,
discount_total DECIMAL(15,2) DEFAULT 0.0,
total_amount DECIMAL(15,2) NOT NULL,
status VARCHAR(50) DEFAULT 'DRAFT', -- DRAFT, SENT, PAID, PARTIAL, OVERDUE, CANCELLED
subtotal DECIMAL(15, 2) NOT NULL,
tax_total DECIMAL(15, 2) DEFAULT 0.0,
discount_total DECIMAL(15, 2) DEFAULT 0.0,
total_amount DECIMAL(15, 2) NOT NULL,
status VARCHAR(50) DEFAULT 'DRAFT',
notes TEXT,
-- EMI tracking fields
is_emi BOOLEAN DEFAULT FALSE,
emi_amount DECIMAL(15,2),
emi_cycle VARCHAR(20), -- MONTHLY, WEEKLY
emi_amount DECIMAL(15, 2),
emi_cycle VARCHAR(20),
emi_start_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
@@ -381,35 +453,36 @@ CREATE TABLE IF NOT EXISTS invoices (
CREATE TABLE IF NOT EXISTS invoice_items (
id SERIAL PRIMARY KEY,
invoice_id INTEGER REFERENCES invoices(id) ON DELETE CASCADE,
product_id INTEGER REFERENCES products(id),
inventory_item_id INTEGER REFERENCES inventory_items(id),
product_id INTEGER REFERENCES products(id) ON DELETE SET NULL,
inventory_item_id INTEGER REFERENCES inventory_items(id) ON DELETE SET NULL,
hsn_code VARCHAR(50),
description VARCHAR(255),
quantity DECIMAL(10,3) NOT NULL,
unit_price DECIMAL(15,2) NOT NULL,
tax_rate DECIMAL(5,2) DEFAULT 0.0,
discount DECIMAL(15,2) DEFAULT 0.0,
making_charge DECIMAL(15,2) DEFAULT 0.0,
other_charges DECIMAL(15,2) DEFAULT 0.0,
total DECIMAL(15,2) NOT NULL
quantity DECIMAL(10, 3) NOT NULL,
unit_price DECIMAL(15, 2) NOT NULL,
tax_rate DECIMAL(5, 2) DEFAULT 0.0,
discount DECIMAL(15, 2) DEFAULT 0.0,
making_charge DECIMAL(15, 2) DEFAULT 0.0,
other_charges DECIMAL(15, 2) DEFAULT 0.0,
total DECIMAL(15, 2) NOT NULL
);
CREATE TABLE IF NOT EXISTS invoice_payments (
id SERIAL PRIMARY KEY,
invoice_id INTEGER REFERENCES invoices(id) ON DELETE CASCADE,
transaction_id INTEGER REFERENCES transactions(id) ON DELETE CASCADE,
amount DECIMAL(15,2) NOT NULL,
transaction_id INTEGER REFERENCES transactions(id) ON DELETE SET NULL,
amount DECIMAL(15, 2) NOT NULL,
payment_date DATE NOT NULL,
emi_installment_number INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 9. Projects & Task Management
CREATE TABLE IF NOT EXISTS projects (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
customer_id INTEGER REFERENCES customers(id),
user_id INTEGER REFERENCES users(id),
customer_id INTEGER REFERENCES customers(id) ON DELETE SET NULL,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
budget DECIMAL(15, 2) DEFAULT 0.00,
status VARCHAR(50) DEFAULT 'ACTIVE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
@@ -421,9 +494,9 @@ CREATE TABLE IF NOT EXISTS project_tasks (
title VARCHAR(255) NOT NULL,
description TEXT,
assignee_name VARCHAR(255),
assignee_user_id INTEGER REFERENCES users(id),
status VARCHAR(50) DEFAULT 'TODO', -- TODO, IN_PROGRESS, REVIEW, DONE
is_billable BOOLEAN DEFAULT false,
assignee_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
status VARCHAR(50) DEFAULT 'TODO',
is_billable BOOLEAN DEFAULT FALSE,
hourly_rate DECIMAL(15, 2) DEFAULT 0.00,
hours_logged DECIMAL(10, 2) DEFAULT 0.00,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
@@ -432,44 +505,8 @@ CREATE TABLE IF NOT EXISTS project_tasks (
CREATE TABLE IF NOT EXISTS project_task_comments (
id SERIAL PRIMARY KEY,
task_id INTEGER REFERENCES project_tasks(id) ON DELETE CASCADE,
user_id INTEGER REFERENCES users(id),
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
content TEXT NOT NULL,
images TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- ACCOUNT SETUP FLOW MIGRATIONS --
ALTER TABLE users ADD COLUMN IF NOT EXISTS username VARCHAR(255) UNIQUE;
ALTER TABLE users ADD COLUMN IF NOT EXISTS name VARCHAR(255);
ALTER TABLE users ADD COLUMN IF NOT EXISTS mobile_number VARCHAR(255);
ALTER TABLE users ADD COLUMN IF NOT EXISTS setup_status VARCHAR(50) DEFAULT 'NOT_STARTED';
ALTER TABLE users ADD COLUMN IF NOT EXISTS setup_completed_at TIMESTAMP;
ALTER TABLE business_profiles ADD COLUMN IF NOT EXISTS nature_of_business VARCHAR(50);
ALTER TABLE business_profiles ADD COLUMN IF NOT EXISTS msme_number VARCHAR(255);
ALTER TABLE business_profiles ALTER COLUMN pan_number TYPE VARCHAR(255);
ALTER TABLE business_profiles ALTER COLUMN gstin TYPE VARCHAR(255);
ALTER TABLE product_categories ADD COLUMN IF NOT EXISTS has_child BOOLEAN DEFAULT FALSE;
ALTER TABLE product_categories ADD COLUMN IF NOT EXISTS default_hsn VARCHAR(50);
ALTER TABLE product_categories ADD COLUMN IF NOT EXISTS default_gst DECIMAL(5, 2);
ALTER TABLE product_categories ADD COLUMN IF NOT EXISTS huid_required BOOLEAN DEFAULT FALSE;
ALTER TABLE product_categories ADD COLUMN IF NOT EXISTS default_making_charge DECIMAL(15, 2);
ALTER TABLE product_categories ADD COLUMN IF NOT EXISTS making_charge_type VARCHAR(50);
ALTER TABLE product_categories ADD COLUMN IF NOT EXISTS is_active BOOLEAN DEFAULT TRUE;
ALTER TABLE product_categories ADD COLUMN IF NOT EXISTS sort_order INTEGER DEFAULT 0;
ALTER TABLE product_categories DROP COLUMN IF EXISTS is_commodity;
ALTER TABLE product_categories DROP COLUMN IF EXISTS daily_rate;
CREATE TABLE IF NOT EXISTS user_consents (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
consent_type VARCHAR(100) NOT NULL,
policy_version VARCHAR(50) NOT NULL,
accepted BOOLEAN DEFAULT TRUE,
accepted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR(100),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

View File

@@ -1,26 +0,0 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class RunSchema {
public static void main(String[] args) {
String url = "jdbc:postgresql://localhost:5432/kifi_db";
String user = "postgres";
String password = "postgres";
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement()) {
stmt.execute("ALTER TABLE purchase_orders ADD COLUMN IF NOT EXISTS cgst_total NUMERIC(10,2)");
stmt.execute("ALTER TABLE purchase_orders ADD COLUMN IF NOT EXISTS sgst_total NUMERIC(10,2)");
stmt.execute("ALTER TABLE purchase_orders ADD COLUMN IF NOT EXISTS igst_total NUMERIC(10,2)");
stmt.execute("ALTER TABLE purchase_order_items ADD COLUMN IF NOT EXISTS cgst_rate NUMERIC(10,2)");
stmt.execute("ALTER TABLE purchase_order_items ADD COLUMN IF NOT EXISTS sgst_rate NUMERIC(10,2)");
stmt.execute("ALTER TABLE purchase_order_items ADD COLUMN IF NOT EXISTS igst_rate NUMERIC(10,2)");
System.out.println("Schema updated successfully!");
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -1,26 +1,13 @@
package com.kifi.api;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.kifi.api.repository.business.BusinessProfileRepository;
import com.kifi.api.entity.business.BusinessProfile;
import java.time.LocalDateTime;
@SpringBootTest
public class DBTest {
@Autowired
private BusinessProfileRepository repo;
@Test
public void test() {
BusinessProfile bp = BusinessProfile.builder().userId(100L).build();
bp.setBusinessName("Test");
bp.setAddress("");
bp.setEmailId("");
bp.setPanNumber("ENC123");
bp.setGstin("ENC123");
bp.setNatureOfBusiness("JEWELLERY");
bp.setMsmeNumber("ENC123");
bp.setCreatedAt(LocalDateTime.now());
bp.setUpdatedAt(LocalDateTime.now());
repo.save(bp).block();
public void contextLoads() {
System.out.println("Spring Boot test context loaded successfully.");
}
}