MukeshKapoor25 commited on
Commit
7a2fa70
Β·
1 Parent(s): a8f0e45

feat(receipts): implement PO-optional GRN creation with migration scripts

Browse files

- Make po_id nullable in scm_grn table to allow GRN creation without Purchase Orders
- Make po_item_id nullable in scm_grn_item table for flexible item linking
- Make batch_no nullable in scm_grn_item table to support optional batch tracking
- Update ReceiptsService to generate temporary UUID for po_item_id when not provided
- Add Python migration script with asyncpg for database schema updates
- Add SQL migration script for direct database execution
- Enable warehouse receipt workflows independent of PO requirements

app/purchases/receipts/services/service.py CHANGED
@@ -116,7 +116,7 @@ class ReceiptsService:
116
  grn_item = ScmGrnItem(
117
  grn_item_id=grn_item_id,
118
  grn_id=grn.grn_id,
119
- po_item_id=item_data.po_item_id, # Can be None now
120
  catalogue_id=item_data.catalogue_id,
121
  sku=item_data.sku,
122
  recv_qty=item_data.recv_qty,
 
116
  grn_item = ScmGrnItem(
117
  grn_item_id=grn_item_id,
118
  grn_id=grn.grn_id,
119
+ po_item_id=item_data.po_item_id or uuid4(), # Temporary: use dummy UUID if None
120
  catalogue_id=item_data.catalogue_id,
121
  sku=item_data.sku,
122
  recv_qty=item_data.recv_qty,
migration_make_po_optional.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Migration script to make PO optional in GRN tables.
4
+ This allows creating GRNs without requiring a Purchase Order.
5
+ """
6
+
7
+ import asyncio
8
+ import asyncpg
9
+ import os
10
+ from dotenv import load_dotenv
11
+
12
+ # Load environment variables
13
+ load_dotenv()
14
+
15
+ async def run_migration():
16
+ """Run the database migration to make PO fields optional"""
17
+
18
+ # Database connection parameters
19
+ db_config = {
20
+ 'host': os.getenv('POSTGRES_HOST', 'ep-sweet-surf-a1qeduoy.ap-southeast-1.aws.neon.tech'),
21
+ 'port': int(os.getenv('POSTGRES_PORT', 5432)),
22
+ 'database': os.getenv('POSTGRES_DB', 'cuatrolabs'),
23
+ 'user': os.getenv('POSTGRES_USER', 'trans_owner'),
24
+ 'password': os.getenv('POSTGRES_PASSWORD'),
25
+ 'ssl': 'require'
26
+ }
27
+
28
+ print("πŸ”„ Starting migration: Make PO optional in GRN tables")
29
+ print(f"πŸ“‘ Connecting to: {db_config['host']}:{db_config['port']}/{db_config['database']}")
30
+
31
+ try:
32
+ # Connect to database
33
+ conn = await asyncpg.connect(**db_config)
34
+ print("βœ… Connected to database")
35
+
36
+ # Start transaction
37
+ async with conn.transaction():
38
+ print("\nπŸ“ Executing migration steps...")
39
+
40
+ # Step 1: Make po_id nullable in scm_grn table
41
+ print("1️⃣ Making po_id nullable in scm_grn table...")
42
+ await conn.execute("""
43
+ ALTER TABLE scm_grn
44
+ ALTER COLUMN po_id DROP NOT NULL;
45
+ """)
46
+ print(" βœ… scm_grn.po_id is now nullable")
47
+
48
+ # Step 2: Make po_item_id nullable in scm_grn_item table
49
+ print("2️⃣ Making po_item_id nullable in scm_grn_item table...")
50
+ await conn.execute("""
51
+ ALTER TABLE scm_grn_item
52
+ ALTER COLUMN po_item_id DROP NOT NULL;
53
+ """)
54
+ print(" βœ… scm_grn_item.po_item_id is now nullable")
55
+
56
+ # Step 3: Make batch_no nullable in scm_grn_item table (if not already)
57
+ print("3️⃣ Making batch_no nullable in scm_grn_item table...")
58
+ await conn.execute("""
59
+ ALTER TABLE scm_grn_item
60
+ ALTER COLUMN batch_no DROP NOT NULL;
61
+ """)
62
+ print(" βœ… scm_grn_item.batch_no is now nullable")
63
+
64
+ print("\nπŸŽ‰ Migration completed successfully!")
65
+ print("πŸ“‹ Summary of changes:")
66
+ print(" β€’ scm_grn.po_id: NOT NULL β†’ NULL")
67
+ print(" β€’ scm_grn_item.po_item_id: NOT NULL β†’ NULL")
68
+ print(" β€’ scm_grn_item.batch_no: NOT NULL β†’ NULL")
69
+ print("\nπŸ’‘ GRNs can now be created without Purchase Orders!")
70
+
71
+ await conn.close()
72
+ print("πŸ”Œ Database connection closed")
73
+
74
+ except Exception as e:
75
+ print(f"❌ Migration failed: {str(e)}")
76
+ raise
77
+
78
+ if __name__ == "__main__":
79
+ asyncio.run(run_migration())
migration_make_po_optional.sql ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -- Migration: Make PO optional in GRN tables
2
+ -- This allows creating GRNs without requiring a Purchase Order
3
+
4
+ -- Step 1: Make po_id nullable in scm_grn table
5
+ ALTER TABLE scm_grn
6
+ ALTER COLUMN po_id DROP NOT NULL;
7
+
8
+ -- Step 2: Make po_item_id nullable in scm_grn_item table
9
+ ALTER TABLE scm_grn_item
10
+ ALTER COLUMN po_item_id DROP NOT NULL;
11
+
12
+ -- Step 3: Make batch_no nullable in scm_grn_item table
13
+ ALTER TABLE scm_grn_item
14
+ ALTER COLUMN batch_no DROP NOT NULL;
15
+
16
+ -- Verify the changes
17
+ SELECT
18
+ table_name,
19
+ column_name,
20
+ is_nullable,
21
+ data_type
22
+ FROM information_schema.columns
23
+ WHERE table_name IN ('scm_grn', 'scm_grn_item')
24
+ AND column_name IN ('po_id', 'po_item_id', 'batch_no')
25
+ ORDER BY table_name, column_name;