Corin1998 commited on
Commit
b748d8b
·
verified ·
1 Parent(s): 08d5ae2

Upload 4 files

Browse files
Files changed (1) hide show
  1. main.py +16 -9
main.py CHANGED
@@ -5,7 +5,7 @@ SQLite + SQLModel + FastAPI
5
  """
6
 
7
  from __future__ import annotations
8
- from typing import Optional, List
9
  from datetime import datetime, date
10
  import os
11
  import pathlib
@@ -137,7 +137,7 @@ class InvoiceItem(SQLModel, table=True):
137
  invoice: Optional[Invoice] = Relationship(back_populates="items")
138
 
139
  # --------------------------
140
- # Totals
141
  # --------------------------
142
  class MoneyBreakdown(BaseModel):
143
  subtotal: float
@@ -147,13 +147,22 @@ class MoneyBreakdown(BaseModel):
147
  def round2(v: float) -> float:
148
  return float(f"{v:.2f}")
149
 
150
- def compute_totals(items: list[dict]) -> MoneyBreakdown:
 
 
 
 
 
 
151
  subtotal = 0.0
152
  tax = 0.0
153
  for it in items:
154
- line = it["quantity"] * it["unit_price"]
 
 
 
155
  subtotal += line
156
- tax += line * it.get("tax_rate", 0.0)
157
  return MoneyBreakdown(subtotal=round2(subtotal), tax=round2(tax), total=round2(subtotal + tax))
158
 
159
  # --------------------------
@@ -176,7 +185,6 @@ def custom_openapi():
176
  description="Mini Invoice/Estimate SaaS API",
177
  routes=app.routes,
178
  )
179
- # securitySchemes を追加
180
  openapi_schema.setdefault("components", {}).setdefault("securitySchemes", {})
181
  openapi_schema["components"]["securitySchemes"]["APIKeyHeader"] = {
182
  "type": "apiKey",
@@ -242,7 +250,7 @@ def get_quote(quote_id: int, session: Session = Depends(get_session)):
242
  if not q:
243
  raise HTTPException(404, "Quote not found")
244
  items = session.exec(select(QuoteItem).where(QuoteItem.quote_id == quote_id)).all()
245
- totals = compute_totals([it.dict() for it in items])
246
  return {"quote": q, "items": items, "totals": totals}
247
 
248
  @app.post("/quotes/{quote_id}/items", dependencies=[Depends(require_api_key)])
@@ -267,7 +275,7 @@ def get_invoice(invoice_id: int, session: Session = Depends(get_session)):
267
  if not inv:
268
  raise HTTPException(404, "Invoice not found")
269
  items = session.exec(select(InvoiceItem).where(InvoiceItem.invoice_id == invoice_id)).all()
270
- totals = compute_totals([it.dict() for it in items])
271
  return {"invoice": inv, "items": items, "totals": totals}
272
 
273
  @app.post("/invoices/{invoice_id}/items", dependencies=[Depends(require_api_key)])
@@ -285,4 +293,3 @@ def root():
285
  # -------- ChatGPT router を最後に組み込む(app 定義後) --------
286
  from openai_integration import router as ai_router
287
  app.include_router(ai_router, prefix="/ai", tags=["ai"])
288
-
 
5
  """
6
 
7
  from __future__ import annotations
8
+ from typing import Optional, List, Any
9
  from datetime import datetime, date
10
  import os
11
  import pathlib
 
137
  invoice: Optional[Invoice] = Relationship(back_populates="items")
138
 
139
  # --------------------------
140
+ # Totals(堅牢化)
141
  # --------------------------
142
  class MoneyBreakdown(BaseModel):
143
  subtotal: float
 
147
  def round2(v: float) -> float:
148
  return float(f"{v:.2f}")
149
 
150
+ def _get(v: Any, key: str, default=0.0):
151
+ # モデルでも dict でもOKにする
152
+ if isinstance(v, dict):
153
+ return v.get(key, default)
154
+ return getattr(v, key, default)
155
+
156
+ def compute_totals(items: list[Any]) -> MoneyBreakdown:
157
  subtotal = 0.0
158
  tax = 0.0
159
  for it in items:
160
+ qty = float(_get(it, "quantity", 0) or 0)
161
+ unit = float(_get(it, "unit_price", 0) or 0)
162
+ rate = float(_get(it, "tax_rate", 0) or 0)
163
+ line = qty * unit
164
  subtotal += line
165
+ tax += line * rate
166
  return MoneyBreakdown(subtotal=round2(subtotal), tax=round2(tax), total=round2(subtotal + tax))
167
 
168
  # --------------------------
 
185
  description="Mini Invoice/Estimate SaaS API",
186
  routes=app.routes,
187
  )
 
188
  openapi_schema.setdefault("components", {}).setdefault("securitySchemes", {})
189
  openapi_schema["components"]["securitySchemes"]["APIKeyHeader"] = {
190
  "type": "apiKey",
 
250
  if not q:
251
  raise HTTPException(404, "Quote not found")
252
  items = session.exec(select(QuoteItem).where(QuoteItem.quote_id == quote_id)).all()
253
+ totals = compute_totals(items) # dict化せず、そのまま渡す
254
  return {"quote": q, "items": items, "totals": totals}
255
 
256
  @app.post("/quotes/{quote_id}/items", dependencies=[Depends(require_api_key)])
 
275
  if not inv:
276
  raise HTTPException(404, "Invoice not found")
277
  items = session.exec(select(InvoiceItem).where(InvoiceItem.invoice_id == invoice_id)).all()
278
+ totals = compute_totals(items)
279
  return {"invoice": inv, "items": items, "totals": totals}
280
 
281
  @app.post("/invoices/{invoice_id}/items", dependencies=[Depends(require_api_key)])
 
293
  # -------- ChatGPT router を最後に組み込む(app 定義後) --------
294
  from openai_integration import router as ai_router
295
  app.include_router(ai_router, prefix="/ai", tags=["ai"])