diff --git a/app/(app)/clients/new.tsx b/app/(app)/clients/new.tsx
index 85409dc..39943b6 100644
--- a/app/(app)/clients/new.tsx
+++ b/app/(app)/clients/new.tsx
@@ -151,25 +151,26 @@ export default function NewClientScreen() {
startDate: new Date().toISOString(),
});
- // 3. Create installation ticket
- const ticketRes = await api.post('/api/v1/tickets', {
- clientId: client.id,
- subject: `New Installation — ${firstName.trim()} ${lastName.trim()}`,
- type: 'INSTALLATION',
- priority: 'NORMAL',
- // Pass subType so activation ticket knows to gate on payment for PREPAID
- ...(subType === 'PREPAID' ? { priority: 'HIGH' } : {}),
- });
- const ticket = ticketRes.data;
+ // 3. Fetch the auto-created installation ticket (API creates one on client creation)
+ let ticket: any = null;
+ try {
+ const ticketsRes = await api.get(`/api/v1/tickets?clientId=${client.id}&type=INSTALLATION&limit=1`);
+ const items = ticketsRes.data?.data ?? ticketsRes.data ?? [];
+ ticket = items[0] ?? null;
+ } catch {}
Alert.alert(
'Client Onboarded! 🎉',
`${firstName} ${lastName} has been registered.\n\nAn installation ticket has been created.`,
[{
- text: 'View Ticket',
+ text: ticket ? 'View Ticket' : 'View Client',
onPress: () => {
- router.replace('/(app)/clients');
- setTimeout(() => router.push(`/(app)/tasks/${ticket.id}`), 300);
+ if (ticket) {
+ router.replace('/(app)/clients');
+ setTimeout(() => router.push(`/(app)/tasks/${ticket.id}`), 300);
+ } else {
+ router.replace('/(app)/clients');
+ }
},
}, {
text: 'Done',
diff --git a/app/(app)/leads/[id].tsx b/app/(app)/leads/[id].tsx
index f93b9e0..3c5c511 100644
--- a/app/(app)/leads/[id].tsx
+++ b/app/(app)/leads/[id].tsx
@@ -72,14 +72,13 @@ export default function LeadDetailScreen() {
});
const client = clientRes.data;
- // Create installation ticket
- const ticketRes = await api.post('/api/v1/tickets', {
- clientId: client.id,
- subject: `New Installation — ${lead.firstName} ${lead.lastName !== '—' ? lead.lastName : ''}`.trim(),
- type: 'INSTALLATION',
- priority: 'NORMAL',
- });
- const ticket = ticketRes.data;
+ // Fetch the auto-created installation ticket (API creates one on client creation)
+ let ticket: any = null;
+ try {
+ const tRes = await api.get(`/api/v1/tickets?clientId=${client.id}&type=INSTALLATION&limit=1`);
+ const items = tRes.data?.data ?? tRes.data ?? [];
+ ticket = items[0] ?? null;
+ } catch {}
// Mark lead as CONVERTED
await api.patch(`/api/v1/leads/${id}`, {
diff --git a/app/(app)/tasks/[id].tsx b/app/(app)/tasks/[id].tsx
index bce78ed..95e4cbb 100644
--- a/app/(app)/tasks/[id].tsx
+++ b/app/(app)/tasks/[id].tsx
@@ -147,13 +147,12 @@ export default function TicketDetailScreen() {
: `Installation confirmed. Location recorded: ${coordStr}`;
await api.post(`/api/v1/tickets/${id}/messages`, { body: note }).catch(() => {});
- // 4. Create follow-up activation ticket
+ // 4. Create follow-up activation ticket (non-fatal if fails for role reasons)
await api.post('/api/v1/tickets', {
- clientId: ticket?.clientId,
- subject: `Account Activation — ${ticket?.client?.firstName ?? ''} ${ticket?.client?.lastName ?? ''}`.trim(),
- type: 'BILLING',
- priority: 'NORMAL',
- description: `Follow-up after installation confirmed. Please activate the client account and generate the first invoice.\n\nInstallation ref: ${id}\nLocation: ${coordStr}`,
+ clientId: ticket?.clientId,
+ subject: `Account Activation — ${ticket?.client?.firstName ?? ''} ${ticket?.client?.lastName ?? ''}`.trim(),
+ type: 'BILLING',
+ priority: 'NORMAL',
}).catch(() => {});
setInstNotes('');
@@ -222,17 +221,26 @@ export default function TicketDetailScreen() {
const planPrice = Number(sub?.monthlyPrice ?? 0);
const submitPrepaidPayment = async () => {
- const amt = parseFloat(prepaidPayAmount);
+ const effectiveAmount = prepaidPayAmount || String(planPrice);
+ const amt = parseFloat(effectiveAmount);
if (!amt || amt <= 0) { Alert.alert('Invalid Amount', 'Enter a valid amount.'); return; }
setPrepaidPaying(true);
try {
- // 1. Record payment
+ // 1. Generate first invoice for client
+ let invoiceId: string | undefined;
+ try {
+ const invRes = await api.post(`/api/v1/invoices/generate/${ticket.clientId}`);
+ invoiceId = invRes.data?.id;
+ } catch {}
+
+ // 2. Record payment (link to invoice if available)
await api.post('/api/v1/payments', {
clientId: ticket.clientId,
amount: amt,
channel: prepaidPayMethod,
paymentDate: new Date().toISOString(),
notes: 'First prepaid payment — account activation',
+ ...(invoiceId ? { invoiceId } : {}),
});
// 2. Activate subscription
if (sub?.id) {
@@ -366,11 +374,11 @@ export default function TicketDetailScreen() {
{/* Amount */}
Amount
{/* Method */}
@@ -388,7 +396,7 @@ export default function TicketDetailScreen() {