-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinvoice_workflow.php
More file actions
457 lines (375 loc) · 17.4 KB
/
invoice_workflow.php
File metadata and controls
457 lines (375 loc) · 17.4 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
<?php
/**
* Complete Invoice Workflow Example
*
* This example demonstrates a comprehensive invoice management workflow using
* Paystack Payment Requests API. It covers the entire invoice lifecycle from
* creation to payment verification.
*
* Workflow Steps:
* 1. Customer management (create/get customer)
* 2. Create draft payment request
* 3. Update invoice with additional items
* 4. Finalize and send to customer
* 5. Monitor payment status
*
* Use Cases:
* - Monthly service billing
* - Project-based invoicing
* - Progressive billing (add items over time)
* - Professional service billing
*
* Before running:
* 1. Replace the secret key with your test key
* 2. Run: php examples/invoice_workflow.php
*/
// Include Composer autoloader
require_once __DIR__ . '/../vendor/autoload.php';
// Import the Paystack Client
use StarfolkSoftware\Paystack\Client as PaystackClient;
// ============================================================================
// Configuration
// ============================================================================
$secretKey = 'sk_test_your_secret_key_here';
// Initialize the Paystack client
$paystack = new PaystackClient([
'secretKey' => $secretKey,
]);
// Customer information for this example
$customerInfo = [
'email' => 'john.doe@techcompany.com',
'first_name' => 'John',
'last_name' => 'Doe',
'phone' => '+2348123456789',
'company' => 'Tech Company Ltd.',
'address' => '123 Business Avenue, Lagos, Nigeria'
];
// ============================================================================
// Helper Functions
// ============================================================================
/**
* Format currency for display
*/
function formatCurrency(int $amountInKobo): string {
return '₦' . number_format($amountInKobo / 100, 2);
}
/**
* Print section header
*/
function printSection(string $title): void {
echo "\n" . str_repeat('=', 60) . "\n";
echo " " . strtoupper($title) . "\n";
echo str_repeat('=', 60) . "\n";
}
/**
* Print step information
*/
function printStep(int $step, string $description): void {
echo "\n🚀 Step {$step}: {$description}\n";
echo str_repeat('-', 50) . "\n";
}
// ============================================================================
// Start Invoice Workflow
// ============================================================================
printSection("Complete Invoice Workflow");
echo "This example demonstrates professional invoice management\n";
echo "Customer: {$customerInfo['first_name']} {$customerInfo['last_name']} ({$customerInfo['email']})\n";
try {
// ========================================================================
// Step 1: Customer Management
// ========================================================================
printStep(1, "Customer Management");
$customerCode = null;
try {
// Try to create customer (might already exist)
echo "Creating customer profile...\n";
$customer = $paystack->customers->create([
'email' => $customerInfo['email'],
'first_name' => $customerInfo['first_name'],
'last_name' => $customerInfo['last_name'],
'phone' => $customerInfo['phone'],
'metadata' => [
'company' => $customerInfo['company'],
'address' => $customerInfo['address'],
'registration_date' => date('Y-m-d'),
'customer_type' => 'business'
]
]);
$customerCode = $customer['data']['customer_code'];
echo "✅ New customer created successfully\n";
echo " Customer Code: {$customerCode}\n";
echo " Customer ID: {$customer['data']['id']}\n";
} catch (Exception $e) {
// Customer likely already exists
echo "ℹ️ Customer creation note: {$e->getMessage()}\n";
try {
// Try to fetch existing customer
echo "Fetching existing customer...\n";
$existingCustomer = $paystack->customers->fetch($customerInfo['email']);
if ($existingCustomer['status']) {
$customerCode = $existingCustomer['data']['customer_code'];
echo "✅ Found existing customer\n";
echo " Customer Code: {$customerCode}\n";
echo " Total Transactions: {$existingCustomer['data']['transactions_count']}\n";
echo " Total Value: " . formatCurrency($existingCustomer['data']['total_transaction_value']) . "\n";
}
} catch (Exception $fetchError) {
// For demo purposes, use a placeholder
echo "⚠️ Using placeholder customer for demo\n";
$customerCode = 'demo_customer_' . time();
}
}
// ========================================================================
// Step 2: Create Draft Payment Request
// ========================================================================
printStep(2, "Creating Draft Invoice");
echo "Creating draft payment request with initial items...\n";
$draftPaymentRequest = $paystack->paymentRequests->create([
'description' => 'Monthly Service Invoice - ' . date('F Y'),
// Initial line items (more can be added later)
'line_items' => [
[
'name' => 'Basic Cloud Hosting',
'amount' => 25000, // ₦250.00
'quantity' => 1,
'description' => 'Monthly cloud hosting service'
],
[
'name' => 'Domain Registration',
'amount' => 5000, // ₦50.00
'quantity' => 1,
'description' => 'Annual domain registration'
]
],
'customer' => $customerCode,
'due_date' => date('Y-m-d', strtotime('+30 days')), // 30 days from now
'draft' => true, // Create as draft initially
'has_invoice' => true, // Generate professional invoice number
'currency' => 'NGN',
// Additional metadata for tracking
'metadata' => [
'invoice_type' => 'monthly_service',
'billing_period' => date('Y-m'),
'created_by' => 'billing_system',
'department' => 'hosting_services'
]
]);
if (!$draftPaymentRequest['status']) {
throw new Exception("Failed to create draft payment request: " . $draftPaymentRequest['message']);
}
$requestCode = $draftPaymentRequest['data']['request_code'];
$invoiceNumber = $draftPaymentRequest['data']['invoice_number'];
$currentAmount = $draftPaymentRequest['data']['amount'];
echo "✅ Draft payment request created successfully\n";
echo " Request Code: {$requestCode}\n";
echo " Invoice Number: #{$invoiceNumber}\n";
echo " Current Amount: " . formatCurrency($currentAmount) . "\n";
echo " Status: {$draftPaymentRequest['data']['status']}\n";
echo " Due Date: {$draftPaymentRequest['data']['due_date']}\n";
// ========================================================================
// Step 3: Add Additional Services (Update Invoice)
// ========================================================================
printStep(3, "Adding Additional Services");
echo "Simulating additional services being added to the invoice...\n";
// In a real scenario, these might be added over time as services are rendered
$updatedRequest = $paystack->paymentRequests->update($requestCode, [
'line_items' => [
// Original items
[
'name' => 'Basic Cloud Hosting',
'amount' => 25000,
'quantity' => 1,
'description' => 'Monthly cloud hosting service'
],
[
'name' => 'Domain Registration',
'amount' => 5000,
'quantity' => 1,
'description' => 'Annual domain registration'
],
// Additional services
[
'name' => 'Premium Support',
'amount' => 15000, // ₦150.00
'quantity' => 1,
'description' => '24/7 premium technical support'
],
[
'name' => 'SSL Certificate',
'amount' => 8000, // ₦80.00
'quantity' => 1,
'description' => 'Wildcard SSL certificate'
],
[
'name' => 'Backup Storage',
'amount' => 3000, // ₦30.00
'quantity' => 5, // 5 GB
'description' => 'Additional backup storage (per GB)'
]
],
// Add applicable taxes
'tax' => [
[
'name' => 'VAT (7.5%)',
'amount' => 4275 // 7.5% of ₦570 = ₦42.75
]
],
// Update description to reflect changes
'description' => 'Monthly Service Invoice - ' . date('F Y') . ' (Comprehensive Package)',
// Add discount if applicable
'discount' => [
[
'name' => 'Early Payment Discount',
'amount' => 2000 // ₦20.00 discount
]
]
]);
if (!$updatedRequest['status']) {
throw new Exception("Failed to update payment request: " . $updatedRequest['message']);
}
$newAmount = $updatedRequest['data']['amount'];
echo "✅ Invoice updated with additional services\n";
echo " Previous Amount: " . formatCurrency($currentAmount) . "\n";
echo " New Amount: " . formatCurrency($newAmount) . "\n";
echo " Difference: " . formatCurrency($newAmount - $currentAmount) . "\n";
// Show detailed breakdown
echo "\n📋 Invoice Breakdown:\n";
if (isset($updatedRequest['data']['line_items'])) {
$subtotal = 0;
foreach ($updatedRequest['data']['line_items'] as $item) {
$lineTotal = $item['amount'] * $item['quantity'];
$subtotal += $lineTotal;
echo " • {$item['name']}: " . formatCurrency($item['amount'])
. " × {$item['quantity']} = " . formatCurrency($lineTotal) . "\n";
}
echo " Subtotal: " . formatCurrency($subtotal) . "\n";
}
if (isset($updatedRequest['data']['tax'])) {
foreach ($updatedRequest['data']['tax'] as $tax) {
echo " + {$tax['name']}: " . formatCurrency($tax['amount']) . "\n";
}
}
if (isset($updatedRequest['data']['discount'])) {
foreach ($updatedRequest['data']['discount'] as $discount) {
echo " - {$discount['name']}: " . formatCurrency($discount['amount']) . "\n";
}
}
echo " Total: " . formatCurrency($newAmount) . "\n";
// ========================================================================
// Step 4: Finalize and Send Invoice
// ========================================================================
printStep(4, "Finalizing and Sending Invoice");
echo "Finalizing the payment request...\n";
// Finalize the payment request (converts from draft to active)
$finalizedRequest = $paystack->paymentRequests->finalize($requestCode, [
'send_notification' => false // We'll send notification manually for better control
]);
if (!$finalizedRequest['status']) {
throw new Exception("Failed to finalize payment request: " . $finalizedRequest['message']);
}
echo "✅ Payment request finalized successfully\n";
echo " Status: {$finalizedRequest['data']['status']}\n";
// Send email notification to customer
echo "\nSending invoice notification to customer...\n";
$notification = $paystack->paymentRequests->sendNotification($requestCode);
if ($notification['status']) {
echo "✅ Invoice notification sent successfully\n";
echo " Notification sent to: {$customerInfo['email']}\n";
echo " Customer can view and pay the invoice online\n";
} else {
echo "⚠️ Warning: Could not send notification - {$notification['message']}\n";
}
// ========================================================================
// Step 5: Payment Status Monitoring
// ========================================================================
printStep(5, "Payment Status Monitoring");
echo "Checking current payment status...\n";
// Verify payment request status
$verifiedRequest = $paystack->paymentRequests->verify($requestCode);
if (!$verifiedRequest['status']) {
throw new Exception("Failed to verify payment request: " . $verifiedRequest['message']);
}
$verification = $verifiedRequest['data'];
echo "📊 Payment Status Report:\n";
echo " Invoice Number: #{$verification['invoice_number']}\n";
echo " Request Code: {$verification['request_code']}\n";
echo " Status: " . ucfirst($verification['status']) . "\n";
echo " Amount: " . formatCurrency($verification['amount']) . "\n";
echo " Amount Paid: " . formatCurrency($verification['amount_paid']) . "\n";
echo " Amount Due: " . formatCurrency($verification['amount'] - $verification['amount_paid']) . "\n";
echo " Paid: " . ($verification['paid'] ? '✅ Yes' : '❌ No') . "\n";
echo " Created: {$verification['created_at']}\n";
echo " Due Date: {$verification['due_date']}\n";
// Show payment URLs if available
if (isset($verification['pdf_url'])) {
echo "\n🔗 Customer Links:\n";
echo " PDF Invoice: {$verification['pdf_url']}\n";
}
if (isset($verification['invoice_url'])) {
echo " Payment Page: {$verification['invoice_url']}\n";
}
// ========================================================================
// Additional Features Demo
// ========================================================================
printStep(6, "Additional Features");
echo "Demonstrating additional invoice features...\n";
// Get payment request totals (summary across all payment requests)
echo "\nFetching account payment request totals...\n";
$totals = $paystack->paymentRequests->totals();
if ($totals['status']) {
$totalsData = $totals['data'];
echo "📈 Account Summary:\n";
echo " Total Payment Requests: {$totalsData['total_requests']}\n";
echo " Pending Amount: " . formatCurrency($totalsData['pending_amount']) . "\n";
echo " Successful Amount: " . formatCurrency($totalsData['successful_amount']) . "\n";
}
echo "\n💡 Next Steps in Real Application:\n";
echo " • Set up webhook endpoints to monitor payment events\n";
echo " • Implement automatic payment reminders for overdue invoices\n";
echo " • Create recurring payment requests for subscription billing\n";
echo " • Generate PDF invoices with your company branding\n";
echo " • Integrate with your accounting/CRM system\n";
// ========================================================================
// Workflow Completion
// ========================================================================
printSection("Workflow Completed Successfully");
echo "🎉 Invoice workflow completed successfully!\n\n";
echo "📋 Summary:\n";
echo " ✅ Customer managed\n";
echo " ✅ Draft invoice created\n";
echo " ✅ Additional services added\n";
echo " ✅ Invoice finalized and sent\n";
echo " ✅ Payment status monitored\n\n";
echo "📊 Final Invoice Details:\n";
echo " Invoice #: {$invoiceNumber}\n";
echo " Customer: {$customerInfo['first_name']} {$customerInfo['last_name']}\n";
echo " Amount: " . formatCurrency($verification['amount']) . "\n";
echo " Status: " . ucfirst($verification['status']) . "\n";
echo " Due: {$verification['due_date']}\n\n";
echo "🔧 Integration Examples:\n";
echo " • payment_request_demo.php - Advanced payment request features\n";
echo " • recurring_billing.php - Subscription and recurring payments\n";
echo " • webhook_handler.php - Real-time payment notifications\n\n";
} catch (Exception $e) {
echo "\n❌ Error in invoice workflow: " . $e->getMessage() . "\n";
echo " Please check your API key and network connection.\n";
echo " For troubleshooting, see: docs/troubleshooting.md\n\n";
exit(1);
}
// ============================================================================
// Development Notes
// ============================================================================
if ($secretKey === 'sk_test_your_secret_key_here') {
echo "⚠️ IMPORTANT: Update your API key!\n";
echo " Replace 'sk_test_your_secret_key_here' with your actual test key\n";
echo " Get it from: https://dashboard.paystack.com/#/settings/developer\n\n";
}
echo "🧪 Testing Notes:\n";
echo " • This example uses test mode (safe for experimentation)\n";
echo " • Use test card 4084084084084081 for successful payments\n";
echo " • Check your Paystack dashboard for real-time updates\n";
echo " • Enable test webhooks for complete integration testing\n\n";
echo "📚 Learn More:\n";
echo " • Paystack API Docs: https://paystack.com/docs/api/\n";
echo " • SDK Documentation: docs/\n";
echo " • GitHub Repository: https://github.com/starfolksoftware/paystack-php\n";