mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
Add ACMCC app source, Supabase backend, and project config
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.45.0";
|
||||
|
||||
const corsHeaders = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
|
||||
};
|
||||
|
||||
function addInterval(dateStr: string, freq: string): string {
|
||||
const d = new Date(dateStr + "T12:00:00");
|
||||
switch (freq) {
|
||||
case "weekly": d.setDate(d.getDate() + 7); break;
|
||||
case "biweekly": d.setDate(d.getDate() + 14); break;
|
||||
case "monthly": d.setMonth(d.getMonth() + 1); break;
|
||||
case "quarterly": d.setMonth(d.getMonth() + 3); break;
|
||||
case "semiannual": d.setMonth(d.getMonth() + 6); break;
|
||||
case "annual": d.setFullYear(d.getFullYear() + 1); break;
|
||||
default: d.setMonth(d.getMonth() + 1);
|
||||
}
|
||||
return d.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
if (req.method === "OPTIONS") return new Response("ok", { headers: corsHeaders });
|
||||
|
||||
const supabase = createClient(
|
||||
Deno.env.get("SUPABASE_URL")!,
|
||||
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
|
||||
);
|
||||
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
const { data: due, error } = await supabase
|
||||
.from("invoices")
|
||||
.select("*")
|
||||
.not("recurrence_frequency", "is", null)
|
||||
.lte("next_generation_date", today);
|
||||
|
||||
if (error) {
|
||||
return new Response(JSON.stringify({ error: error.message }), {
|
||||
status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
let created = 0;
|
||||
const errors: string[] = [];
|
||||
|
||||
for (const tmpl of due || []) {
|
||||
try {
|
||||
if (tmpl.recurrence_end_date && tmpl.next_generation_date > tmpl.recurrence_end_date) continue;
|
||||
|
||||
const issueDate = tmpl.next_generation_date || today;
|
||||
const dueOffset = tmpl.due_date && tmpl.issue_date
|
||||
? Math.round((new Date(tmpl.due_date).getTime() - new Date(tmpl.issue_date).getTime()) / 86400000)
|
||||
: 30;
|
||||
const newDue = new Date(issueDate + "T12:00:00");
|
||||
newDue.setDate(newDue.getDate() + dueOffset);
|
||||
|
||||
const { error: insErr } = await supabase.from("invoices").insert({
|
||||
association_id: tmpl.association_id,
|
||||
vendor_name: tmpl.vendor_name,
|
||||
invoice_number: tmpl.invoice_number ? `${tmpl.invoice_number}-${issueDate}` : null,
|
||||
amount: tmpl.amount,
|
||||
status: "pending",
|
||||
issue_date: issueDate,
|
||||
due_date: newDue.toISOString().slice(0, 10),
|
||||
description: tmpl.description,
|
||||
category: tmpl.category,
|
||||
line_items: tmpl.line_items,
|
||||
rate: tmpl.rate,
|
||||
parent_invoice_id: tmpl.id,
|
||||
});
|
||||
if (insErr) { errors.push(insErr.message); continue; }
|
||||
|
||||
const next = addInterval(issueDate, tmpl.recurrence_frequency);
|
||||
const stop = tmpl.recurrence_end_date && next > tmpl.recurrence_end_date;
|
||||
await supabase.from("invoices").update({
|
||||
next_generation_date: stop ? null : next,
|
||||
recurrence_frequency: stop ? null : tmpl.recurrence_frequency,
|
||||
}).eq("id", tmpl.id);
|
||||
|
||||
created++;
|
||||
} catch (e) {
|
||||
errors.push(String(e));
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ created, errors }), {
|
||||
headers: { ...corsHeaders, "Content-Type": "application/json" },
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user