Spaces:
Build error
Build error
File size: 5,689 Bytes
5e52bd7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | from sqlalchemy.orm import Session
from datetime import datetime
from app.models.tender import TenderModel
from app.models.oc import OCModel
from app.services.mercado_publico import fetch_tenders, get_tender_by_code
from app.services.mercado_publico_oc import get_ocs_by_date
import json
async def sync_tenders_to_db(db: Session, keyword: str = None):
"""
Fetches real tenders from Mercado Público API and saves them.
"""
print(f"[Sync] Starting REAL synchronization... keyword={keyword}")
try:
api_tenders = await fetch_tenders(keyword=keyword)
if not api_tenders:
print("[Sync] No active tenders found for today in the API.")
return {"new": 0, "updated": 0, "message": "No new tenders found"}
print(f"[Sync] API returned {len(api_tenders)} real tenders for processing.")
except Exception as e:
print(f"[Sync] API error: {e}")
return {"new": 0, "updated": 0, "message": f"API Error: {str(e)}"}
count_new = 0
count_updated = 0
# Deduplicate API results by code to avoid IntegrityError within the same batch
seen_codes = set()
unique_tenders = []
for t in api_tenders:
if t.code not in seen_codes:
seen_codes.add(t.code)
unique_tenders.append(t)
for api_t in unique_tenders:
# Check if exists
db_tender = db.query(TenderModel).filter(TenderModel.code == api_t.code).first()
# Helper to parse dates
def parse_dt(dt_str):
if not dt_str: return None
try:
# Handle Z and other common formats
clean_str = dt_str.replace("Z", "").split(".")[0]
return datetime.fromisoformat(clean_str)
except:
return None
# Convert Pydantic model to dict for DB
tender_data = {
"code": api_t.code,
"name": api_t.name,
"buyer": api_t.buyer,
"buyer_region": api_t.buyer_region,
"status": api_t.status,
"status_code": str(api_t.status_code) if api_t.status_code else None,
"type": api_t.type,
"currency": api_t.currency,
"closing_date": parse_dt(api_t.closing_date) if isinstance(api_t.closing_date, str) else api_t.closing_date,
"publication_date": parse_dt(api_t.publication_date) if isinstance(api_t.publication_date, str) else api_t.publication_date,
"description": api_t.description,
"estimated_amount": api_t.estimated_amount,
"source": api_t.source,
"region": api_t.region,
"sector": api_t.sector,
"items": [item.model_dump() for item in api_t.items] if api_t.items else [],
"attachments": api_t.attachments,
"evaluation_criteria": api_t.evaluation_criteria,
"contract_duration": api_t.contract_duration
}
if db_tender:
# Update existing
for key, value in tender_data.items():
setattr(db_tender, key, value)
count_updated += 1
else:
# Create new
new_tender = TenderModel(**tender_data)
db.add(new_tender)
count_new += 1
db.commit()
print(f"[Sync] Finished. New: {count_new}, Updated: {count_updated}")
return {"new": count_new, "updated": count_updated}
async def sync_purchase_orders_to_db(db: Session, date: str = None, status: str = "todos"):
"""
Fetches purchase orders from Mercado Público and saves them in the local database.
"""
if not date:
date = datetime.now().strftime("%d%m%Y")
try:
api_orders = await get_ocs_by_date(date, status)
if not api_orders:
print(f"[Sync OC] No purchase orders found for date={date} status={status}")
return {"new": 0, "updated": 0, "message": "No purchase orders found"}
except Exception as e:
print(f"[Sync OC] API error: {e}")
return {"new": 0, "updated": 0, "message": f"API Error: {str(e)}"}
count_new = 0
count_updated = 0
seen_codes = set()
for oc in api_orders:
if oc.code in seen_codes:
continue
seen_codes.add(oc.code)
db_oc = db.query(OCModel).filter(OCModel.code == oc.code).first()
oc_data = {
"code": oc.code,
"name": oc.name,
"status": oc.status,
"status_code": oc.status_code,
"buyer": oc.buyer,
"buyer_rut": oc.buyer_rut,
"provider": oc.provider,
"provider_rut": oc.provider_rut,
"date_creation": oc.date_creation,
"total_amount": oc.total_amount,
"currency": oc.currency,
"type": oc.type,
"items": [item.model_dump() for item in oc.items] if oc.items else [],
"raw_data": oc.raw_data,
}
if db_oc:
for key, value in oc_data.items():
setattr(db_oc, key, value)
count_updated += 1
else:
new_oc = OCModel(**oc_data)
db.add(new_oc)
count_new += 1
db.commit()
print(f"[Sync OC] Finished. New: {count_new}, Updated: {count_updated}")
return {"new": count_new, "updated": count_updated}
def clean_expired_tenders(db: Session):
"""
Removes tenders where closing_date is in the past.
"""
now = datetime.now()
expired = db.query(TenderModel).filter(TenderModel.closing_date < now).delete()
db.commit()
print(f"[Sync] Cleaned {expired} expired tenders.")
return expired
|