Álvaro Valenzuela Valdes commited on
Commit ·
b294142
1
Parent(s): 604982f
Fix Market Monitor timezone issues and DBManager styling typo (cleaned)
Browse files
backend/app/routers/oc.py
CHANGED
|
@@ -19,8 +19,9 @@ async def list_purchase_orders(
|
|
| 19 |
List purchase orders for a specific date (ddmmaaaa).
|
| 20 |
"""
|
| 21 |
if not date:
|
| 22 |
-
from datetime import datetime
|
| 23 |
-
|
|
|
|
| 24 |
|
| 25 |
# Try to fetch current OC data from the live API
|
| 26 |
ocs = await get_ocs_by_date(date, status)
|
|
|
|
| 19 |
List purchase orders for a specific date (ddmmaaaa).
|
| 20 |
"""
|
| 21 |
if not date:
|
| 22 |
+
from datetime import datetime, timedelta, timezone
|
| 23 |
+
chile_tz = timezone(timedelta(hours=-4))
|
| 24 |
+
date = datetime.now(chile_tz).strftime("%d%m%Y")
|
| 25 |
|
| 26 |
# Try to fetch current OC data from the live API
|
| 27 |
ocs = await get_ocs_by_date(date, status)
|
backend/app/services/mercado_publico.py
CHANGED
|
@@ -257,7 +257,8 @@ async def get_tenders_by_filters(
|
|
| 257 |
else:
|
| 258 |
# Default to today if no date is provided for specific filters
|
| 259 |
if status or org_code or provider_code:
|
| 260 |
-
|
|
|
|
| 261 |
|
| 262 |
if status:
|
| 263 |
# Map friendly status to MP codes
|
|
@@ -288,7 +289,8 @@ async def fetch_tenders(
|
|
| 288 |
date: Optional[str] = None,
|
| 289 |
type_code: Optional[str] = None
|
| 290 |
) -> List[Tender]:
|
| 291 |
-
|
|
|
|
| 292 |
|
| 293 |
if not date:
|
| 294 |
tenders = await get_active_tenders()
|
|
|
|
| 257 |
else:
|
| 258 |
# Default to today if no date is provided for specific filters
|
| 259 |
if status or org_code or provider_code:
|
| 260 |
+
chile_tz = timezone(timedelta(hours=-4))
|
| 261 |
+
params["fecha"] = datetime.now(chile_tz).strftime("%d%m%Y")
|
| 262 |
|
| 263 |
if status:
|
| 264 |
# Map friendly status to MP codes
|
|
|
|
| 289 |
date: Optional[str] = None,
|
| 290 |
type_code: Optional[str] = None
|
| 291 |
) -> List[Tender]:
|
| 292 |
+
chile_tz = timezone(timedelta(hours=-4))
|
| 293 |
+
search_date = normalize_mp_date(date if date else datetime.now(chile_tz).strftime("%Y-%m-%d"))
|
| 294 |
|
| 295 |
if not date:
|
| 296 |
tenders = await get_active_tenders()
|
backend/app/services/sync.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
from sqlalchemy.orm import Session
|
| 2 |
-
from datetime import datetime
|
| 3 |
from app.models.tender import TenderModel
|
| 4 |
from app.models.oc import OCModel
|
| 5 |
from app.services.mercado_publico import fetch_tenders, get_tender_by_code
|
|
@@ -91,7 +91,8 @@ async def sync_purchase_orders_to_db(db: Session, date: str = None, status: str
|
|
| 91 |
Fetches purchase orders from Mercado Público and saves them in the local database.
|
| 92 |
"""
|
| 93 |
if not date:
|
| 94 |
-
|
|
|
|
| 95 |
|
| 96 |
try:
|
| 97 |
api_orders = await get_ocs_by_date(date, status)
|
|
@@ -147,7 +148,8 @@ def clean_expired_tenders(db: Session):
|
|
| 147 |
"""
|
| 148 |
Removes tenders where closing_date is in the past.
|
| 149 |
"""
|
| 150 |
-
|
|
|
|
| 151 |
expired = db.query(TenderModel).filter(TenderModel.closing_date < now).delete()
|
| 152 |
db.commit()
|
| 153 |
print(f"[Sync] Cleaned {expired} expired tenders.")
|
|
|
|
| 1 |
from sqlalchemy.orm import Session
|
| 2 |
+
from datetime import datetime, timedelta, timezone
|
| 3 |
from app.models.tender import TenderModel
|
| 4 |
from app.models.oc import OCModel
|
| 5 |
from app.services.mercado_publico import fetch_tenders, get_tender_by_code
|
|
|
|
| 91 |
Fetches purchase orders from Mercado Público and saves them in the local database.
|
| 92 |
"""
|
| 93 |
if not date:
|
| 94 |
+
chile_tz = timezone(timedelta(hours=-4))
|
| 95 |
+
date = datetime.now(chile_tz).strftime("%d%m%Y")
|
| 96 |
|
| 97 |
try:
|
| 98 |
api_orders = await get_ocs_by_date(date, status)
|
|
|
|
| 148 |
"""
|
| 149 |
Removes tenders where closing_date is in the past.
|
| 150 |
"""
|
| 151 |
+
chile_tz = timezone(timedelta(hours=-4))
|
| 152 |
+
now = datetime.now(chile_tz)
|
| 153 |
expired = db.query(TenderModel).filter(TenderModel.closing_date < now).delete()
|
| 154 |
db.commit()
|
| 155 |
print(f"[Sync] Cleaned {expired} expired tenders.")
|
frontend/components/DBManager.tsx
CHANGED
|
@@ -31,9 +31,9 @@ export default function DBManager({ onFilterClick, lang }: Props) {
|
|
| 31 |
setMessage(null);
|
| 32 |
try {
|
| 33 |
const result = await syncDatabase();
|
| 34 |
-
setMessage({
|
| 35 |
-
type: 'success',
|
| 36 |
-
text: `Sync complete! New: ${result.tenders?.new || 0} tenders, ${result.purchase_orders?.new || 0} OCs.`
|
| 37 |
});
|
| 38 |
await loadStats();
|
| 39 |
} catch (e) {
|
|
@@ -45,7 +45,7 @@ export default function DBManager({ onFilterClick, lang }: Props) {
|
|
| 45 |
|
| 46 |
const handleClear = async () => {
|
| 47 |
if (!confirm("Are you sure you want to delete ALL local tenders and purchase orders? This cannot be undone.")) return;
|
| 48 |
-
|
| 49 |
setIsActionInProgress(true);
|
| 50 |
setMessage(null);
|
| 51 |
try {
|
|
@@ -74,7 +74,7 @@ export default function DBManager({ onFilterClick, lang }: Props) {
|
|
| 74 |
<h2 className="text-3xl font-black text-white tracking-tight">{t.databaseTitle}</h2>
|
| 75 |
<p className="text-slate-400 mt-1">{t.databaseDesc}</p>
|
| 76 |
</div>
|
| 77 |
-
|
| 78 |
<div className="flex items-center gap-3">
|
| 79 |
<button
|
| 80 |
onClick={handleSync}
|
|
@@ -131,8 +131,8 @@ export default function DBManager({ onFilterClick, lang }: Props) {
|
|
| 131 |
</h3>
|
| 132 |
<div className="space-y-4">
|
| 133 |
{stats?.top_buyers?.map((buyer: any, idx: number) => (
|
| 134 |
-
<button
|
| 135 |
-
key={idx}
|
| 136 |
onClick={() => onFilterClick?.("buyer", buyer.name)}
|
| 137 |
className="w-full flex items-center justify-between p-4 rounded-2xl bg-white/[0.03] border border-white/5 hover:bg-white/[0.08] hover:border-cyan/30 transition-all group/row cursor-pointer text-left"
|
| 138 |
>
|
|
@@ -156,14 +156,14 @@ export default function DBManager({ onFilterClick, lang }: Props) {
|
|
| 156 |
<span>💡</span> Persistence Insights
|
| 157 |
</h3>
|
| 158 |
<div className="space-y-6">
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
</div>
|
| 168 |
</div>
|
| 169 |
</div>
|
|
|
|
| 31 |
setMessage(null);
|
| 32 |
try {
|
| 33 |
const result = await syncDatabase();
|
| 34 |
+
setMessage({
|
| 35 |
+
type: 'success',
|
| 36 |
+
text: `Sync complete! New: ${result.tenders?.new || 0} tenders, ${result.purchase_orders?.new || 0} OCs.`
|
| 37 |
});
|
| 38 |
await loadStats();
|
| 39 |
} catch (e) {
|
|
|
|
| 45 |
|
| 46 |
const handleClear = async () => {
|
| 47 |
if (!confirm("Are you sure you want to delete ALL local tenders and purchase orders? This cannot be undone.")) return;
|
| 48 |
+
|
| 49 |
setIsActionInProgress(true);
|
| 50 |
setMessage(null);
|
| 51 |
try {
|
|
|
|
| 74 |
<h2 className="text-3xl font-black text-white tracking-tight">{t.databaseTitle}</h2>
|
| 75 |
<p className="text-slate-400 mt-1">{t.databaseDesc}</p>
|
| 76 |
</div>
|
| 77 |
+
|
| 78 |
<div className="flex items-center gap-3">
|
| 79 |
<button
|
| 80 |
onClick={handleSync}
|
|
|
|
| 131 |
</h3>
|
| 132 |
<div className="space-y-4">
|
| 133 |
{stats?.top_buyers?.map((buyer: any, idx: number) => (
|
| 134 |
+
<button
|
| 135 |
+
key={idx}
|
| 136 |
onClick={() => onFilterClick?.("buyer", buyer.name)}
|
| 137 |
className="w-full flex items-center justify-between p-4 rounded-2xl bg-white/[0.03] border border-white/5 hover:bg-white/[0.08] hover:border-cyan/30 transition-all group/row cursor-pointer text-left"
|
| 138 |
>
|
|
|
|
| 156 |
<span>💡</span> Persistence Insights
|
| 157 |
</h3>
|
| 158 |
<div className="space-y-6">
|
| 159 |
+
<div className="p-4 rounded-2xl bg-blue-500/5 border border-blue-500/10">
|
| 160 |
+
<p className="text-xs text-blue-400 font-bold mb-1">Local Mode Active</p>
|
| 161 |
+
<p className="text-xs text-slate-400 leading-relaxed">System is prioritizing local database for faster search. Global sync updates the local cache with the latest Mercado Público data.</p>
|
| 162 |
+
</div>
|
| 163 |
+
<div className="p-4 rounded-2xl bg-purple-500/5 border border-purple-500/10">
|
| 164 |
+
<p className="text-xs text-purple-400 font-bold mb-1">Integrity Check</p>
|
| 165 |
+
<p className="text-xs text-slate-400 leading-relaxed">All nested data (attachments, items, criteria) is successfully serialized as JSON in the SQLite storage.</p>
|
| 166 |
+
</div>
|
| 167 |
</div>
|
| 168 |
</div>
|
| 169 |
</div>
|