VanithaSivaraj commited on
Commit
165d873
·
1 Parent(s): e3c6991

(invoice): implement global meta schema for invoice module with audit information

Browse files
app/trade_invoices/controllers/router.py CHANGED
@@ -50,11 +50,13 @@ async def create_invoice(
50
  """
51
  try:
52
  created_by = current_user.user_id
 
53
 
54
  invoice, errors = await TradeInvoiceService.create_draft_invoice(
55
  db=db,
56
  invoice_data=invoice_data,
57
- created_by=created_by
 
58
  )
59
 
60
  if errors:
@@ -165,12 +167,14 @@ async def edit_invoice(
165
  """
166
  try:
167
  updated_by = current_user.user_id
 
168
 
169
  invoice, errors = await TradeInvoiceService.edit_draft_invoice(
170
  db=db,
171
  invoice_id=invoice_id,
172
  invoice_data=invoice_data,
173
- updated_by=updated_by
 
174
  )
175
 
176
  if errors:
@@ -226,12 +230,14 @@ async def update_invoice_status(
226
  """
227
  try:
228
  performed_by = current_user.user_id
 
229
 
230
  invoice, errors = await TradeInvoiceService.update_invoice_status(
231
  db=db,
232
  invoice_id=invoice_id,
233
  action_request=action_request,
234
- performed_by=performed_by
 
235
  )
236
 
237
  if errors:
 
50
  """
51
  try:
52
  created_by = current_user.user_id
53
+ created_by_username = current_user.username
54
 
55
  invoice, errors = await TradeInvoiceService.create_draft_invoice(
56
  db=db,
57
  invoice_data=invoice_data,
58
+ created_by=created_by,
59
+ created_by_username=created_by_username
60
  )
61
 
62
  if errors:
 
167
  """
168
  try:
169
  updated_by = current_user.user_id
170
+ updated_by_username = current_user.username
171
 
172
  invoice, errors = await TradeInvoiceService.edit_draft_invoice(
173
  db=db,
174
  invoice_id=invoice_id,
175
  invoice_data=invoice_data,
176
+ updated_by=updated_by,
177
+ updated_by_username=updated_by_username
178
  )
179
 
180
  if errors:
 
230
  """
231
  try:
232
  performed_by = current_user.user_id
233
+ performed_by_username = current_user.username
234
 
235
  invoice, errors = await TradeInvoiceService.update_invoice_status(
236
  db=db,
237
  invoice_id=invoice_id,
238
  action_request=action_request,
239
+ performed_by=performed_by,
240
+ performed_by_username=performed_by_username
241
  )
242
 
243
  if errors:
app/trade_invoices/models/model.py CHANGED
@@ -99,8 +99,11 @@ class ScmInvoice(Base):
99
 
100
  # Audit fields
101
  created_by = Column(String(64), nullable=True)
 
102
  created_at = Column(DateTime(timezone=True), nullable=False, server_default=func.now())
103
  updated_at = Column(DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now())
 
 
104
 
105
  # Relationships
106
  items = relationship("ScmInvoiceItem", back_populates="invoice", cascade="all, delete-orphan")
 
99
 
100
  # Audit fields
101
  created_by = Column(String(64), nullable=True)
102
+ created_by_username = Column(String(128), nullable=True)
103
  created_at = Column(DateTime(timezone=True), nullable=False, server_default=func.now())
104
  updated_at = Column(DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now())
105
+ updated_by = Column(String(64), nullable=True)
106
+ updated_by_username = Column(String(128), nullable=True)
107
 
108
  # Relationships
109
  items = relationship("ScmInvoiceItem", back_populates="invoice", cascade="all, delete-orphan")
app/trade_invoices/services/service.py CHANGED
@@ -13,6 +13,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
13
  from sqlalchemy import select, and_, func, text
14
  from sqlalchemy.orm import selectinload
15
 
 
16
  from app.trade_invoices.models.model import ScmInvoice, ScmInvoiceItem, ScmInvoiceStatusLog
17
  from app.trade_invoices.schemas.schema import (
18
  GSTModel, InvoiceCreate, InvoiceActionRequest, InvoiceValidationError, POItemModel, POShipmentSummary, POSummaryModel, PricingModel, PurchaseOrderResponseModel, QuantityModel
@@ -39,7 +40,8 @@ class TradeInvoiceService:
39
  async def create_draft_invoice(
40
  db: AsyncSession,
41
  invoice_data: InvoiceCreate,
42
- created_by: str
 
43
  ) -> Tuple[ScmInvoice, List[InvoiceValidationError]]:
44
  """
45
  Create draft invoice (PO-driven, no GRN)
@@ -130,7 +132,9 @@ class TradeInvoiceService:
130
  round_off_amt=invoice_data.additional_charges.round_off or 0,
131
 
132
  remarks=invoice_data.remarks,
133
- created_by=created_by
 
 
134
  )
135
 
136
  db.add(invoice)
@@ -306,7 +310,8 @@ class TradeInvoiceService:
306
  db: AsyncSession,
307
  invoice_id: UUID,
308
  action_request: InvoiceActionRequest,
309
- performed_by: str
 
310
  ) -> Tuple[ScmInvoice, List[InvoiceValidationError]]:
311
  """
312
  Update invoice status following state machine rules
@@ -350,6 +355,8 @@ class TradeInvoiceService:
350
  # Update invoice
351
  invoice.status = new_status
352
  invoice.updated_at = dt.datetime.utcnow()
 
 
353
 
354
  # Create status log
355
  status_log = ScmInvoiceStatusLog(
@@ -460,7 +467,7 @@ class TradeInvoiceService:
460
  dict(row) for row in logs_result.mappings().all()
461
  ]
462
 
463
- return response
464
 
465
  @staticmethod
466
  async def list_invoices(
@@ -523,7 +530,10 @@ class TradeInvoiceService:
523
 
524
  query = text(query_str)
525
  result = await db.execute(query, params)
526
- return [dict(row._mapping) for row in result.fetchall()]
 
 
 
527
 
528
  else:
529
 
@@ -545,7 +555,12 @@ class TradeInvoiceService:
545
  i.total_tax_amt,
546
  i.grand_total_amt,
547
  i.status,
548
- i.created_at
 
 
 
 
 
549
  FROM trans.scm_invoice i
550
  JOIN trans.scm_po po
551
  ON po.po_id = i.po_id
@@ -585,7 +600,10 @@ class TradeInvoiceService:
585
  result = await db.execute(text(sql), params)
586
  rows = result.mappings().all()
587
 
588
- return [dict(row) for row in rows]
 
 
 
589
 
590
  @staticmethod
591
  async def get_invoice_summary(
@@ -685,7 +703,7 @@ class TradeInvoiceService:
685
  )
686
 
687
  @staticmethod
688
- async def edit_draft_invoice(db: AsyncSession, invoice_id: str, invoice_data: dict, updated_by: str):
689
  EDITABLE_FIELDS = {
690
  "po_id": lambda v: UUID(v),
691
  "grn_id": lambda v: UUID(v),
@@ -699,6 +717,8 @@ class TradeInvoiceService:
699
  "packing_amt": lambda v: v,
700
  "other_charges_amt": lambda v: v,
701
  "round_off_amt": lambda v: v,
 
 
702
  }
703
  result = await db.execute(
704
  select(ScmInvoice).where(ScmInvoice.invoice_id == invoice_id)
@@ -727,6 +747,8 @@ class TradeInvoiceService:
727
  setattr(invoice, field, transformer(invoice_data[field]))
728
 
729
  invoice.updated_at = dt.datetime.utcnow()
 
 
730
 
731
  await db.commit()
732
  await db.refresh(invoice)
 
13
  from sqlalchemy import select, and_, func, text
14
  from sqlalchemy.orm import selectinload
15
 
16
+ from app.core.utils import format_meta_field
17
  from app.trade_invoices.models.model import ScmInvoice, ScmInvoiceItem, ScmInvoiceStatusLog
18
  from app.trade_invoices.schemas.schema import (
19
  GSTModel, InvoiceCreate, InvoiceActionRequest, InvoiceValidationError, POItemModel, POShipmentSummary, POSummaryModel, PricingModel, PurchaseOrderResponseModel, QuantityModel
 
40
  async def create_draft_invoice(
41
  db: AsyncSession,
42
  invoice_data: InvoiceCreate,
43
+ created_by: str,
44
+ created_by_username:str
45
  ) -> Tuple[ScmInvoice, List[InvoiceValidationError]]:
46
  """
47
  Create draft invoice (PO-driven, no GRN)
 
132
  round_off_amt=invoice_data.additional_charges.round_off or 0,
133
 
134
  remarks=invoice_data.remarks,
135
+ created_by=created_by,
136
+ created_by_username=created_by_username,
137
+ created_at=dt.datetime.utcnow()
138
  )
139
 
140
  db.add(invoice)
 
310
  db: AsyncSession,
311
  invoice_id: UUID,
312
  action_request: InvoiceActionRequest,
313
+ performed_by: str,
314
+ performed_by_username:str
315
  ) -> Tuple[ScmInvoice, List[InvoiceValidationError]]:
316
  """
317
  Update invoice status following state machine rules
 
355
  # Update invoice
356
  invoice.status = new_status
357
  invoice.updated_at = dt.datetime.utcnow()
358
+ invoice.updated_by = performed_by
359
+ invoice.updated_by_username = performed_by_username
360
 
361
  # Create status log
362
  status_log = ScmInvoiceStatusLog(
 
467
  dict(row) for row in logs_result.mappings().all()
468
  ]
469
 
470
+ return format_meta_field(response)
471
 
472
  @staticmethod
473
  async def list_invoices(
 
530
 
531
  query = text(query_str)
532
  result = await db.execute(query, params)
533
+ return [
534
+ format_meta_field(dict(row._mapping))
535
+ for row in result.fetchall()
536
+ ]
537
 
538
  else:
539
 
 
555
  i.total_tax_amt,
556
  i.grand_total_amt,
557
  i.status,
558
+ i.created_at,
559
+ i.updated_at,
560
+ i.created_by,
561
+ i.created_by_username,
562
+ i.updated_by,
563
+ i.updated_by_username
564
  FROM trans.scm_invoice i
565
  JOIN trans.scm_po po
566
  ON po.po_id = i.po_id
 
600
  result = await db.execute(text(sql), params)
601
  rows = result.mappings().all()
602
 
603
+ return [
604
+ format_meta_field(dict(row))
605
+ for row in rows
606
+ ]
607
 
608
  @staticmethod
609
  async def get_invoice_summary(
 
703
  )
704
 
705
  @staticmethod
706
+ async def edit_draft_invoice(db: AsyncSession, invoice_id: str, invoice_data: dict, updated_by: str, updated_by_username:str):
707
  EDITABLE_FIELDS = {
708
  "po_id": lambda v: UUID(v),
709
  "grn_id": lambda v: UUID(v),
 
717
  "packing_amt": lambda v: v,
718
  "other_charges_amt": lambda v: v,
719
  "round_off_amt": lambda v: v,
720
+ "updated_by": lambda v: v,
721
+ "updated_by_username": lambda v: v
722
  }
723
  result = await db.execute(
724
  select(ScmInvoice).where(ScmInvoice.invoice_id == invoice_id)
 
747
  setattr(invoice, field, transformer(invoice_data[field]))
748
 
749
  invoice.updated_at = dt.datetime.utcnow()
750
+ invoice.updated_by = updated_by
751
+ invoice.updated_by_username = updated_by_username
752
 
753
  await db.commit()
754
  await db.refresh(invoice)
app/trade_invoices/utils.py CHANGED
@@ -164,7 +164,7 @@ ALLOWED_INVOICE_PROJECTION_FIELDS = [
164
  "currency", "invoice_date", "payment_terms", "due_date",
165
  "subtotal_amt", "discount_amt", "taxable_amt", "cgst_amt", "sgst_amt", "igst_amt",
166
  "total_tax_amt", "grand_total_amt", "status", "reverse_charge", "remarks",
167
- "created_by", "created_at", "updated_at"
168
  ]
169
 
170
 
 
164
  "currency", "invoice_date", "payment_terms", "due_date",
165
  "subtotal_amt", "discount_amt", "taxable_amt", "cgst_amt", "sgst_amt", "igst_amt",
166
  "total_tax_amt", "grand_total_amt", "status", "reverse_charge", "remarks",
167
+ "created_by", "created_at", "updated_at", "created_by_username", "updated_by_username"
168
  ]
169
 
170