From 0ca8e05a2aea52d34bf4568633228c21a37c8594 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 4 Aug 2025 16:55:49 +0700 Subject: [PATCH 01/20] [PWTS-38] Add business APIs --- code-samples/business/address.php | 242 ++++++++++ code-samples/business/contact.php | 270 +++++++++++ code-samples/business/e-invoice/discount.php | 313 +++++++++++++ code-samples/business/e-invoice/invoice.php | 395 ++++++++++++++++ code-samples/business/e-invoice/product.php | 333 ++++++++++++++ code-samples/business/e-invoice/tax.php | 281 ++++++++++++ code-samples/business/e-invoice/template.php | 226 +++++++++ code-samples/business/payout.php | 145 ++++++ lib/FasterPay/BusinessGateway.php | 172 +++++++ lib/FasterPay/Gateway.php | 4 +- lib/FasterPay/GatewayInterface.php | 14 + lib/FasterPay/HttpClient.php | 4 +- lib/FasterPay/Response/PaymentResponse.php | 5 +- .../Response/SubscriptionResponse.php | 5 +- lib/FasterPay/Services/Business/Address.php | 254 ++++++++++ lib/FasterPay/Services/Business/Contact.php | 311 +++++++++++++ .../Services/Business/EInvoice/Discount.php | 170 +++++++ .../Services/Business/EInvoice/Invoice.php | 433 ++++++++++++++++++ .../Services/Business/EInvoice/Product.php | 181 ++++++++ .../Services/Business/EInvoice/Tax.php | 156 +++++++ .../Services/Business/EInvoice/Template.php | 148 ++++++ lib/FasterPay/Services/Business/Payout.php | 159 +++++++ lib/FasterPay/Services/HttpService.php | 13 +- lib/FasterPay/Services/Payment.php | 2 +- lib/FasterPay/Services/Pingback.php | 4 +- lib/FasterPay/Services/Signature.php | 4 +- 26 files changed, 4228 insertions(+), 16 deletions(-) create mode 100644 code-samples/business/address.php create mode 100644 code-samples/business/contact.php create mode 100644 code-samples/business/e-invoice/discount.php create mode 100644 code-samples/business/e-invoice/invoice.php create mode 100644 code-samples/business/e-invoice/product.php create mode 100644 code-samples/business/e-invoice/tax.php create mode 100644 code-samples/business/e-invoice/template.php create mode 100644 code-samples/business/payout.php create mode 100644 lib/FasterPay/BusinessGateway.php create mode 100644 lib/FasterPay/GatewayInterface.php create mode 100644 lib/FasterPay/Services/Business/Address.php create mode 100644 lib/FasterPay/Services/Business/Contact.php create mode 100644 lib/FasterPay/Services/Business/EInvoice/Discount.php create mode 100644 lib/FasterPay/Services/Business/EInvoice/Invoice.php create mode 100644 lib/FasterPay/Services/Business/EInvoice/Product.php create mode 100644 lib/FasterPay/Services/Business/EInvoice/Tax.php create mode 100644 lib/FasterPay/Services/Business/EInvoice/Template.php create mode 100644 lib/FasterPay/Services/Business/Payout.php diff --git a/code-samples/business/address.php b/code-samples/business/address.php new file mode 100644 index 0000000..d438712 --- /dev/null +++ b/code-samples/business/address.php @@ -0,0 +1,242 @@ + '', + 'privateKey' => '', + 'isTest' => 1, +]); + +echo "FasterPay Address API Examples\n"; +echo "==============================\n\n"; + +// Example 1: Get address fields for United States +echo "1. Getting address fields for United States\n"; +echo "--------------------------------------------\n"; + +try { + $addressFieldsResponse = $businessGateway->addressService()->getAddressFields('US'); + + if ($addressFieldsResponse->isSuccessful()) { + echo "✓ Address fields retrieved successfully\n"; + $data = $addressFieldsResponse->getDecodeResponse(); + $countryCode = $data['data']['country_code'] ?? 'US'; + $fields = $data['data']['fields'] ?? []; + $subdivisions = $data['data']['subdivisions'] ?? []; + + echo " Country: $countryCode\n"; + echo " Required fields:\n"; + + foreach ($fields as $field) { + $type = $field['type'] ?? 'text'; + $label = $field['label'] ?? ''; + $name = $field['name'] ?? ''; + echo " - $label ($name): $type\n"; + } + + echo " States/subdivisions: " . count($subdivisions) . " available\n"; + echo " Example states: "; + $exampleStates = array_slice($subdivisions, 0, 3); + foreach ($exampleStates as $state) { + echo $state['name'] . ' (' . $state['code'] . ') '; + } + echo "\n"; + } else { + echo "✗ Error: " . $addressFieldsResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 2: Get address fields for Canada +echo "2. Getting address fields for Canada\n"; +echo "------------------------------------\n"; + +try { + $canadaFieldsResponse = $businessGateway->addressService()->getAddressFields('CA'); + + if ($canadaFieldsResponse->isSuccessful()) { + echo "✓ Canadian address fields retrieved\n"; + $data = $canadaFieldsResponse->getDecodeResponse(); + $fields = $data['data']['fields'] ?? []; + + echo " Canada requires " . count($fields) . " fields:\n"; + foreach ($fields as $field) { + echo " - " . ($field['label'] ?? 'Unknown') . "\n"; + } + } else { + echo "✗ Error: " . $canadaFieldsResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Get subdivisions for a country +echo "3. Getting subdivisions (states) for US\n"; +echo "---------------------------------------\n"; + +try { + $subdivisions = $businessGateway->addressService()->getSubdivisions('US'); + + if (!empty($subdivisions)) { + echo "✓ Found " . count($subdivisions) . " US states/territories\n"; + echo " Sample states:\n"; + + // Show first 10 states + $sampleStates = array_slice($subdivisions, 0, 10); + foreach ($sampleStates as $state) { + echo " - {$state['name']} ({$state['code']})\n"; + } + echo " ... and " . (count($subdivisions) - 10) . " more\n"; + } else { + echo "✗ No subdivisions found for US\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Validate address data +echo "4. Validating address data\n"; +echo "--------------------------\n"; + +$sampleAddressData = [ + 'address_line1' => '123 Main Street', + 'locality' => 'New York', + 'administrative_area' => 'NY', + 'postal_code' => '10001' +]; + +try { + $validationResult = $businessGateway->addressService()->validateAddressData($sampleAddressData, 'US'); + + echo "✓ Address validation completed\n"; + echo " Valid: " . ($validationResult['valid'] ? 'Yes' : 'No') . "\n"; + echo " Country: {$validationResult['country_code']}\n"; + + if (!empty($validationResult['errors'])) { + echo " Errors:\n"; + foreach ($validationResult['errors'] as $error) { + echo " - $error\n"; + } + } + + if (!empty($validationResult['warnings'])) { + echo " Warnings:\n"; + foreach ($validationResult['warnings'] as $warning) { + echo " - $warning\n"; + } + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 5: Get address format for multiple countries +echo "5. Getting address formats for multiple countries\n"; +echo "-------------------------------------------------\n"; + +$countries = ['US', 'CA', 'GB', 'DE', 'FR']; + +try { + $addressFields = $businessGateway->addressService()->getMultipleAddressFields($countries); + + echo "✓ Retrieved address fields for multiple countries\n"; + + foreach ($countries as $country) { + if (isset($addressFields[$country])) { + if ($addressFields[$country]->isSuccessful()) { + $data = $addressFields[$country]->getDecodeResponse(); + $fieldCount = count($data['data']['fields'] ?? []); + $subdivisionCount = count($data['data']['subdivisions'] ?? []); + + echo " $country: $fieldCount fields"; + if ($subdivisionCount > 0) { + echo ", $subdivisionCount subdivisions"; + } + echo "\n"; + } else { + echo " $country: Error retrieving data\n"; + } + } else { + echo " $country: Failed to retrieve\n"; + } + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: Search for specific subdivision +echo "6. Searching for California\n"; +echo "---------------------------\n"; + +try { + $searchResults = $businessGateway->addressService()->searchSubdivisions('US', 'California'); + + if (!empty($searchResults)) { + echo "✓ Found " . count($searchResults) . " match(es) for 'California'\n"; + foreach ($searchResults as $result) { + echo " - {$result['name']} ({$result['code']})\n"; + } + } else { + echo "✗ No matches found for 'California'\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: Get specific subdivision by code +echo "7. Getting subdivision details for 'CA' (California)\n"; +echo "----------------------------------------------------\n"; + +try { + $subdivision = $businessGateway->addressService()->getSubdivisionByCode('US', 'CA'); + + if ($subdivision) { + echo "✓ Found subdivision details\n"; + echo " Code: {$subdivision['code']}\n"; + echo " Name: {$subdivision['name']}\n"; + echo " Has children: " . (empty($subdivision['children']) ? 'No' : 'Yes') . "\n"; + } else { + echo "✗ Subdivision 'CA' not found\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: Check if country has subdivisions +echo "8. Checking subdivision support\n"; +echo "-------------------------------\n"; + +$testCountries = ['US', 'GB', 'MC']; // US, UK, Monaco + +foreach ($testCountries as $country) { + try { + $hasSubdivisions = $businessGateway->addressService()->hasSubdivisions($country); + echo " $country: " . ($hasSubdivisions ? 'Has subdivisions' : 'No subdivisions') . "\n"; + } catch (FasterPay\Exception $e) { + echo " $country: Error checking - " . $e->getMessage() . "\n"; + } +} + +echo "\nAddress API examples completed!\n"; +echo "Use cases:\n"; +echo "• Dynamic address form generation\n"; +echo "• Address validation for different countries\n"; +echo "• State/province dropdown population\n"; +echo "• International shipping address collection\n"; +echo "• Address format compliance checking\n"; +echo "• Subdivision code lookup and validation\n"; diff --git a/code-samples/business/contact.php b/code-samples/business/contact.php new file mode 100644 index 0000000..8837056 --- /dev/null +++ b/code-samples/business/contact.php @@ -0,0 +1,270 @@ + '', + 'privateKey' => '', + 'isTest' => 1, +]); + +echo "FasterPay Contact API Examples\n"; +echo "===============================\n\n"; + +// Example 1: Create a new contact +echo "1. Creating a new contact\n"; +echo "-------------------------\n"; + +$contactData = [ + 'type' => 'individual', + 'first_name' => 'Jane', + 'last_name' => 'Smith', + 'email' => 'jane.smith@example.com', + 'phone' => '+1-555-234-5678', + 'company' => 'Tech Solutions Inc', + 'job_title' => 'Product Manager', + 'status' => 'active', + 'tags' => ['customer', 'premium'], + 'notes' => 'High-value customer, prefers email communication', + 'custom_fields' => [ + 'customer_since' => '2023-01-15', + 'preferred_contact_method' => 'email' + ] +]; + +try { + $contactResponse = $businessGateway->contactService()->createContact($contactData); + + if ($contactResponse->isSuccessful()) { + echo "✓ Contact created successfully\n"; + $responseData = $contactResponse->getDecodeResponse(); + $contactId = $responseData['contact_id'] ?? 'contact_' . time(); + echo " Contact ID: $contactId\n"; + echo " Name: {$contactData['first_name']} {$contactData['last_name']}\n"; + echo " Email: {$contactData['email']}\n"; + echo " Phone: {$contactData['phone']}\n"; + } else { + echo "✗ Error: " . $contactResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 2: Create a business contact +echo "2. Creating a business contact\n"; +echo "------------------------------\n"; + +$businessContactData = [ + 'type' => 'business', + 'name' => 'Global Enterprise Solutions', + 'email' => 'contact@globalenterprise.com', + 'phone' => '+1-555-987-6543', + 'website' => 'https://globalenterprise.com', + 'industry' => 'Technology', + 'employee_count' => '500-1000', + 'annual_revenue' => '50000000', + 'status' => 'active', + 'primary_contact' => [ + 'first_name' => 'Robert', + 'last_name' => 'Johnson', + 'email' => 'robert.johnson@globalenterprise.com', + 'job_title' => 'CFO' + ] +]; + +try { + $businessContactResponse = $businessGateway->contactService()->createContact($businessContactData); + + if ($businessContactResponse->isSuccessful()) { + echo "✓ Business contact created successfully\n"; + $responseData = $businessContactResponse->getDecodeResponse(); + $businessContactId = $responseData['contact_id'] ?? 'business_contact_' . time(); + echo " Contact ID: $businessContactId\n"; + echo " Company: {$businessContactData['name']}\n"; + echo " Industry: {$businessContactData['industry']}\n"; + echo " Primary Contact: {$businessContactData['primary_contact']['first_name']} {$businessContactData['primary_contact']['last_name']}\n"; + } else { + echo "✗ Error: " . $businessContactResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Get contact by email +echo "3. Finding contact by email\n"; +echo "---------------------------\n"; + +try { + $emailResponse = $businessGateway->contactService()->getContactByEmail('jane.smith@example.com'); + + if ($emailResponse->isSuccessful()) { + echo "✓ Contact found by email\n"; + $contactData = $emailResponse->getDecodeResponse(); + echo " Email: jane.smith@example.com\n"; + echo " Name: " . ($contactData['first_name'] ?? 'Jane') . " " . ($contactData['last_name'] ?? 'Smith') . "\n"; + echo " Status: " . ($contactData['status'] ?? 'active') . "\n"; + } else { + echo "✗ Error: " . $emailResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Add address to contact +echo "4. Adding address to contact\n"; +echo "----------------------------\n"; + +$contactId = 'contact_' . time(); // In real scenario, use actual contact ID +$addressData = [ + 'type' => 'home', + 'street' => '456 Oak Avenue', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postal_code' => '94102', + 'country_code' => 'US', + 'is_primary' => true +]; + +try { + $addressResponse = $businessGateway->contactService()->addContactAddress($contactId, $addressData); + + if ($addressResponse->isSuccessful()) { + echo "✓ Address added to contact successfully\n"; + echo " Contact ID: $contactId\n"; + echo " Address: {$addressData['street']}, {$addressData['city']}, {$addressData['state']}\n"; + echo " Type: {$addressData['type']}\n"; + } else { + echo "✗ Error: " . $addressResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 5: Search contacts +echo "5. Searching contacts\n"; +echo "---------------------\n"; + +$searchParams = [ + 'query' => 'smith', + 'type' => 'individual', + 'status' => 'active', + 'tags' => ['customer'], + 'limit' => 10 +]; + +try { + $searchResponse = $businessGateway->contactService()->searchContacts($searchParams); + + if ($searchResponse->isSuccessful()) { + echo "✓ Contact search completed\n"; + echo " Query: 'smith'\n"; + echo " Filter: Active individual customers\n"; + echo " (In a real scenario, this would return matching contacts)\n"; + } else { + echo "✗ Error: " . $searchResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: Update contact +echo "6. Updating contact information\n"; +echo "-------------------------------\n"; + +$updateData = [ + 'job_title' => 'Senior Product Manager', + 'phone' => '+1-555-234-9999', + 'notes' => 'Promoted to Senior PM. Updated contact preferences.', + 'custom_fields' => [ + 'last_interaction' => date('Y-m-d'), + 'account_value' => '15000' + ] +]; + +try { + $updateResponse = $businessGateway->contactService()->updateContact($contactId, $updateData); + + if ($updateResponse->isSuccessful()) { + echo "✓ Contact updated successfully\n"; + echo " Contact ID: $contactId\n"; + echo " New job title: {$updateData['job_title']}\n"; + echo " Updated phone: {$updateData['phone']}\n"; + } else { + echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: List contacts with filters +echo "7. Listing contacts with filters\n"; +echo "--------------------------------\n"; + +$filters = [ + 'type' => 'individual', + 'status' => 'active', + 'has_email' => true, + 'created_after' => '2023-01-01', + 'limit' => 25, + 'offset' => 0, + 'sort' => 'last_name', + 'order' => 'asc' +]; + +try { + $listResponse = $businessGateway->contactService()->listContacts($filters); + + if ($listResponse->isSuccessful()) { + echo "✓ Contact list retrieved successfully\n"; + echo " Filter: Active individuals with email addresses\n"; + echo " Created after: 2023-01-01\n"; + echo " Sorted by: Last name (ascending)\n"; + echo " Limit: 25 contacts\n"; + echo " (In a real scenario, this would show actual contact data)\n"; + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: Get contact addresses +echo "8. Getting contact addresses\n"; +echo "----------------------------\n"; + +try { + $addressesResponse = $businessGateway->contactService()->getContactAddresses($contactId); + + if ($addressesResponse->isSuccessful()) { + echo "✓ Contact addresses retrieved successfully\n"; + echo " Contact ID: $contactId\n"; + echo " (In a real scenario, this would show all addresses for the contact)\n"; + } else { + echo "✗ Error: " . $addressesResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\nContact API examples completed!\n"; +echo "Use cases:\n"; +echo "• Customer relationship management (CRM)\n"; +echo "• Contact database management\n"; +echo "• Lead tracking and nurturing\n"; +echo "• Customer support integration\n"; +echo "• Marketing campaign management\n"; +echo "• Sales pipeline management\n"; \ No newline at end of file diff --git a/code-samples/business/e-invoice/discount.php b/code-samples/business/e-invoice/discount.php new file mode 100644 index 0000000..a652a83 --- /dev/null +++ b/code-samples/business/e-invoice/discount.php @@ -0,0 +1,313 @@ + '', + 'privateKey' => '', + 'isTest' => 1, +]); + +echo "FasterPay E-Invoice Discount API Examples\n"; +echo "==========================================\n\n"; + +// Example 1: Create a flat discount +echo "1. Creating a flat discount\n"; +echo "---------------------------\n"; + +$flatDiscountData = [ + 'name' => 'Early Bird Discount', + 'type' => 'flat', + 'value' => 0.1, + 'currency' => 'USD', + 'description' => '$10 discount for early payment' +]; + +try { + $discountResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($flatDiscountData); + + if ($discountResponse->isSuccessful()) { + echo "✓ Flat discount created successfully\n"; + $responseData = $discountResponse->getDecodeResponse(); + $discountId = $responseData['data']['id'] ?? 'DC-' . time(); + echo " Discount ID: $discountId\n"; + echo " Name: {$flatDiscountData['name']}\n"; + echo " Type: {$flatDiscountData['type']}\n"; + echo " Value: $" . $flatDiscountData['value'] . " {$flatDiscountData['currency']}\n"; + echo " Description: {$flatDiscountData['description']}\n"; + } else { + echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 2: Create a percentage discount +echo "2. Creating a percentage discount\n"; +echo "---------------------------------\n"; + +$percentageDiscountData = [ + 'name' => 'Volume Discount', + 'type' => 'percentage', + 'value' => 15, + 'description' => '15% discount for bulk orders' +]; + +try { + $volumeResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($percentageDiscountData); + + if ($volumeResponse->isSuccessful()) { + echo "✓ Percentage discount created successfully\n"; + $responseData = $volumeResponse->getDecodeResponse(); + $volumeDiscountId = $responseData['data']['id'] ?? 'DC-VOLUME-' . time(); + echo " Discount ID: $volumeDiscountId\n"; + echo " Name: {$percentageDiscountData['name']}\n"; + echo " Type: {$percentageDiscountData['type']}\n"; + echo " Value: {$percentageDiscountData['value']}%\n"; + echo " Description: {$percentageDiscountData['description']}\n"; + } else { + echo "✗ Error: " . $volumeResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Create loyalty discount +echo "3. Creating loyalty discount\n"; +echo "----------------------------\n"; + +$loyaltyDiscountData = [ + 'name' => 'Loyal Customer Discount', + 'type' => 'percentage', + 'value' => 10, + 'description' => '10% discount for returning customers' +]; + +try { + $loyaltyResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($loyaltyDiscountData); + + if ($loyaltyResponse->isSuccessful()) { + echo "✓ Loyalty discount created successfully\n"; + $responseData = $loyaltyResponse->getDecodeResponse(); + $loyaltyDiscountId = $responseData['data']['id'] ?? 'DC-LOYALTY-' . time(); + echo " Discount ID: $loyaltyDiscountId\n"; + echo " Value: {$loyaltyDiscountData['value']}% for loyal customers\n"; + } else { + echo "✗ Error: " . $loyaltyResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Get discount details +echo "4. Getting discount details\n"; +echo "---------------------------\n"; + +$discountId = $discountId ?? 'DC-' . time(); + +try { + $detailsResponse = $businessGateway->eInvoiceDiscountService()->getDiscount($discountId); + + if ($detailsResponse->isSuccessful()) { + echo "✓ Discount details retrieved\n"; + $details = $detailsResponse->getDecodeResponse(); + $discount = $details['data'] ?? []; + + echo " ID: " . ($discount['id'] ?? $discountId) . "\n"; + echo " Name: " . ($discount['name'] ?? 'N/A') . "\n"; + echo " Type: " . ($discount['type'] ?? 'N/A') . "\n"; + echo " Value: " . ($discount['value'] ?? 'N/A') . "\n"; + echo " Currency: " . ($discount['currency'] ?? 'N/A') . "\n"; + echo " Description: " . ($discount['description'] ?? 'N/A') . "\n"; + } else { + echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 5: Update discount +echo "5. Updating discount\n"; +echo "--------------------\n"; + +$updateData = [ + 'value' => 0.15, + 'description' => 'Updated to $15 early payment discount' +]; + +try { + $updateResponse = $businessGateway->eInvoiceDiscountService()->updateDiscount($discountId, $updateData); + + if ($updateResponse->isSuccessful()) { + echo "✓ Discount updated successfully\n"; + echo " New value: $" . $updateData['value'] . "\n"; + echo " Updated description: {$updateData['description']}\n"; + } else { + echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: List all discounts +echo "6. Listing all discounts\n"; +echo "------------------------\n"; + +try { + $listResponse = $businessGateway->eInvoiceDiscountService()->listDiscounts(); + + if ($listResponse->isSuccessful()) { + echo "✓ Discount list retrieved\n"; + $listData = $listResponse->getDecodeResponse(); + $discounts = $listData['data']['data'] ?? []; + + echo " Total discounts: " . count($discounts) . "\n"; + + if (!empty($discounts)) { + echo " Available discounts:\n"; + foreach ($discounts as $discount) { + $id = $discount['id'] ?? 'Unknown'; + $name = $discount['name'] ?? 'Unnamed'; + $type = $discount['type'] ?? 'N/A'; + $value = $discount['value'] ?? 0; + $currency = $discount['currency'] ?? ''; + + if ($type === 'percentage') { + echo " - $name ($id): $value% off\n"; + } else { + echo " - $name ($id): $" . $value . " $currency off\n"; + } + } + } + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: Create seasonal discounts +echo "7. Creating seasonal discounts\n"; +echo "------------------------------\n"; + +$seasonalDiscounts = [ + [ + 'name' => 'Black Friday Special', + 'type' => 'percentage', + 'value' => 25, + 'description' => '25% off everything - Black Friday special' + ], + [ + 'name' => 'New Year Discount', + 'type' => 'flat', + 'value' => 50, + 'currency' => 'USD', + 'description' => '$50 off to start the new year right' + ], + [ + 'name' => 'Summer Sale', + 'type' => 'percentage', + 'value' => 20, + 'description' => '20% summer discount on all services' + ] +]; + +$createdSeasonalDiscounts = []; + +foreach ($seasonalDiscounts as $discountData) { + try { + $response = $businessGateway->eInvoiceDiscountService()->createDiscount($discountData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $discountId = $responseData['data']['id'] ?? 'DC-SEASONAL-' . time(); + $createdSeasonalDiscounts[] = $discountId; + + if ($discountData['type'] === 'percentage') { + echo "✓ {$discountData['name']}: {$discountData['value']}% off (ID: $discountId)\n"; + } else { + echo "✓ {$discountData['name']}: $" . $discountData['value'] . " off (ID: $discountId)\n"; + } + } else { + echo "✗ Failed to create {$discountData['name']}: " . $response->getErrors()->getMessage() . "\n"; + } + } catch (FasterPay\Exception $e) { + echo "✗ Exception creating {$discountData['name']}: " . $e->getMessage() . "\n"; + } +} + +echo " Created " . count($createdSeasonalDiscounts) . " seasonal discount offers\n"; + +echo "\n"; + +// Example 8: Create tiered discounts for different customer levels +echo "8. Creating tiered customer discounts\n"; +echo "-------------------------------------\n"; + +$tieredDiscounts = [ + [ + 'name' => 'Bronze Member', + 'type' => 'percentage', + 'value' => 5, + 'description' => '5% discount for Bronze tier customers' + ], + [ + 'name' => 'Silver Member', + 'type' => 'percentage', + 'value' => 10, + 'description' => '10% discount for Silver tier customers' + ], + [ + 'name' => 'Gold Member', + 'type' => 'percentage', + 'value' => 15, + 'description' => '15% discount for Gold tier customers' + ], + [ + 'name' => 'Platinum Member', + 'type' => 'percentage', + 'value' => 20, + 'description' => '20% discount for Platinum tier customers' + ] +]; + +echo "Creating customer tier discounts:\n"; + +foreach ($tieredDiscounts as $tierData) { + try { + $response = $businessGateway->eInvoiceDiscountService()->createDiscount($tierData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $tierId = $responseData['data']['id'] ?? 'DC-TIER-' . time(); + echo " ✓ {$tierData['name']}: {$tierData['value']}% (ID: $tierId)\n"; + } else { + echo " ✗ Failed to create {$tierData['name']}\n"; + } + } catch (FasterPay\Exception $e) { + echo " ✗ Exception creating {$tierData['name']}: " . $e->getMessage() . "\n"; + } +} + +echo "\nE-Invoice Discount API examples completed!\n"; +echo "Use cases:\n"; +echo "• Customer loyalty programs\n"; +echo "• Seasonal and promotional campaigns\n"; +echo "• Volume-based pricing strategies\n"; +echo "• Early payment incentives\n"; +echo "• Tiered customer benefits\n"; +echo "• Dynamic pricing adjustments\n"; +echo "• Bulk order discounts\n"; +echo "• Customer retention strategies\n"; \ No newline at end of file diff --git a/code-samples/business/e-invoice/invoice.php b/code-samples/business/e-invoice/invoice.php new file mode 100644 index 0000000..126810d --- /dev/null +++ b/code-samples/business/e-invoice/invoice.php @@ -0,0 +1,395 @@ + '', + 'privateKey' => '', + 'isTest' => 1, +]); + +echo "FasterPay E-Invoice API Examples\n"; +echo "=================================\n\n"; + +// Example 1: Create a new e-invoice +echo "1. Creating a new e-invoice\n"; +echo "---------------------------\n"; + +$invoiceData = [ + 'invoice_number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'issue_date' => date('Y-m-d'), + 'due_date' => date('Y-m-d', strtotime('+30 days')), + 'currency' => 'USD', + 'status' => 'draft', + 'customer' => [ + 'id' => 'customer_123', + 'name' => 'Acme Corporation', + 'email' => 'billing@acme.com', + 'phone' => '+1-555-123-4567', + 'tax_id' => '12-3456789', + 'billing_address' => [ + 'street' => '123 Business Blvd', + 'city' => 'New York', + 'state' => 'NY', + 'postal_code' => '10001', + 'country_code' => 'US' + ] + ], + 'items' => [ + [ + 'description' => 'Website Development Services', + 'quantity' => 1, + 'unit_price' => 5000.00, + 'tax_rate' => 8.25, + 'category' => 'services' + ], + [ + 'description' => 'Monthly Hosting Package', + 'quantity' => 12, + 'unit_price' => 99.99, + 'tax_rate' => 8.25, + 'category' => 'services' + ], + [ + 'description' => 'SSL Certificate', + 'quantity' => 1, + 'unit_price' => 150.00, + 'tax_rate' => 8.25, + 'category' => 'products' + ] + ], + 'payment_terms' => 'Net 30', + 'notes' => 'Thank you for your business. Payment is due within 30 days.', + 'template' => 'standard', + 'send_automatically' => false +]; + +try { + $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceData); + + if ($invoiceResponse->isSuccessful()) { + echo "✓ E-invoice created successfully\n"; + $responseData = $invoiceResponse->getDecodeResponse(); + $invoiceId = $responseData['invoice_id'] ?? 'inv_' . time(); + echo " Invoice ID: $invoiceId\n"; + echo " Invoice Number: {$invoiceData['invoice_number']}\n"; + echo " Customer: {$invoiceData['customer']['name']}\n"; + + // Calculate totals + $subtotal = 0; + foreach ($invoiceData['items'] as $item) { + $subtotal += $item['quantity'] * $item['unit_price']; + } + $tax = $subtotal * 0.0825; // 8.25% tax + $total = $subtotal + $tax; + + echo " Subtotal: $" . number_format($subtotal, 2) . "\n"; + echo " Tax: $" . number_format($tax, 2) . "\n"; + echo " Total: $" . number_format($total, 2) . "\n"; + } else { + echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 5: Mark invoice as paid +echo "5. Marking invoice as paid\n"; +echo "--------------------------\n"; + +$paymentData = [ + 'amount' => 6558.87, // Total amount from invoice + 'payment_date' => date('Y-m-d'), + 'payment_method' => 'bank_transfer', + 'reference' => 'TXN-' . time(), + 'notes' => 'Payment received via bank transfer' +]; + +try { + $paidResponse = $businessGateway->eInvoiceService()->markAsPaid($invoiceId, $paymentData); + + if ($paidResponse->isSuccessful()) { + echo "✓ Invoice marked as paid successfully\n"; + echo " Invoice ID: $invoiceId\n"; + echo " Amount: $" . number_format($paymentData['amount'], 2) . "\n"; + echo " Payment Date: {$paymentData['payment_date']}\n"; + echo " Method: {$paymentData['payment_method']}\n"; + echo " Reference: {$paymentData['reference']}\n"; + } else { + echo "✗ Error: " . $paidResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: Search invoices +echo "6. Searching invoices\n"; +echo "---------------------\n"; + +$searchParams = [ + 'customer_name' => 'Acme', + 'status' => 'paid', + 'amount_min' => 1000, + 'amount_max' => 10000, + 'date_from' => '2024-01-01', + 'date_to' => '2024-12-31', + 'limit' => 20 +]; + +try { + $searchResponse = $businessGateway->eInvoiceService()->searchInvoices($searchParams); + + if ($searchResponse->isSuccessful()) { + echo "✓ Invoice search completed\n"; + echo " Customer: Contains 'Acme'\n"; + echo " Status: Paid\n"; + echo " Amount range: $1,000 - $10,000\n"; + echo " Date range: 2024\n"; + echo " (In a real scenario, this would return matching invoices)\n"; + } else { + echo "✗ Error: " . $searchResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: List invoices with filters +echo "7. Listing invoices with filters\n"; +echo "--------------------------------\n"; + +$filters = [ + 'status' => 'sent', + 'overdue' => true, + 'currency' => 'USD', + 'limit' => 50, + 'offset' => 0, + 'sort' => 'due_date', + 'order' => 'asc' +]; + +try { + $listResponse = $businessGateway->eInvoiceService()->listInvoices($filters); + + if ($listResponse->isSuccessful()) { + echo "✓ Invoice list retrieved successfully\n"; + echo " Filter: Overdue sent invoices in USD\n"; + echo " Sorted by: Due date (ascending)\n"; + echo " Limit: 50 invoices\n"; + echo " (In a real scenario, this would show actual invoice data)\n"; + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: Get invoice status +echo "8. Getting invoice status\n"; +echo "-------------------------\n"; + +try { + $statusResponse = $businessGateway->eInvoiceService()->getInvoiceStatus($invoiceId); + + if ($statusResponse->isSuccessful()) { + echo "✓ Invoice status retrieved successfully\n"; + $statusData = $statusResponse->getDecodeResponse(); + echo " Invoice ID: $invoiceId\n"; + echo " Status: " . ($statusData['status'] ?? 'paid') . "\n"; + echo " Last updated: " . ($statusData['updated_at'] ?? date('Y-m-d H:i:s')) . "\n"; + echo " Payment status: " . ($statusData['payment_status'] ?? 'completed') . "\n"; + } else { + echo "✗ Error: " . $statusResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 9: Update invoice item +echo "9. Updating invoice item\n"; +echo "------------------------\n"; + +$itemId = 'item_' . time(); // In real scenario, use actual item ID +$itemUpdateData = [ + 'description' => 'Premium Domain Registration (Updated)', + 'unit_price' => 39.99, + 'notes' => 'Upgraded to premium domain package' +]; + +try { + $itemUpdateResponse = $businessGateway->eInvoiceService()->updateInvoiceItem($invoiceId, $itemId, $itemUpdateData); + + if ($itemUpdateResponse->isSuccessful()) { + echo "✓ Invoice item updated successfully\n"; + echo " Invoice ID: $invoiceId\n"; + echo " Item ID: $itemId\n"; + echo " New description: {$itemUpdateData['description']}\n"; + echo " New price: $" . number_format($itemUpdateData['unit_price'], 2) . "\n"; + } else { + echo "✗ Error: " . $itemUpdateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 10: Create recurring invoice template +echo "10. Creating recurring invoice\n"; +echo "------------------------------\n"; + +$recurringInvoiceData = [ + 'template_name' => 'Monthly Hosting Service', + 'invoice_number_pattern' => 'HOST-{YYYY}-{MM}-{####}', + 'recurrence' => 'monthly', + 'start_date' => date('Y-m-d'), + 'end_date' => date('Y-m-d', strtotime('+1 year')), + 'customer' => [ + 'id' => 'customer_456', + 'name' => 'Tech Startup LLC', + 'email' => 'accounts@techstartup.com' + ], + 'items' => [ + [ + 'description' => 'Premium Hosting Package', + 'quantity' => 1, + 'unit_price' => 299.99, + 'tax_rate' => 8.25 + ], + [ + 'description' => 'SSL Certificate Renewal', + 'quantity' => 1, + 'unit_price' => 99.99, + 'tax_rate' => 8.25 + ] + ], + 'auto_send' => true, + 'payment_terms' => 'Net 15' +]; + +try { + $recurringResponse = $businessGateway->eInvoiceService()->createInvoice($recurringInvoiceData); + + if ($recurringResponse->isSuccessful()) { + echo "✓ Recurring invoice template created successfully\n"; + $responseData = $recurringResponse->getDecodeResponse(); + $templateId = $responseData['template_id'] ?? 'template_' . time(); + echo " Template ID: $templateId\n"; + echo " Template Name: {$recurringInvoiceData['template_name']}\n"; + echo " Recurrence: {$recurringInvoiceData['recurrence']}\n"; + echo " Customer: {$recurringInvoiceData['customer']['name']}\n"; + echo " Monthly Amount: $" . number_format(399.98 * 1.0825, 2) . " (including tax)\n"; + } else { + echo "✗ Error: " . $recurringResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\nE-Invoice API examples completed!\n"; +echo "Use cases:\n"; +echo "• Automated billing and invoicing\n"; +echo "• Recurring subscription billing\n"; +echo "• Professional invoice generation\n"; +echo "• Payment tracking and reminders\n"; +echo "• Financial reporting and analytics\n"; +echo "• Multi-currency invoicing\n"; +echo "• Tax compliance and reporting\n"; +echo "• Customer payment portal integration\n"; + +echo "\n"; + +// Example 2: Add item to existing invoice +echo "2. Adding item to invoice\n"; +echo "-------------------------\n"; + +$invoiceId = 'inv_' . time(); // In real scenario, use actual invoice ID +$newItem = [ + 'description' => 'Domain Registration', + 'quantity' => 1, + 'unit_price' => 29.99, + 'tax_rate' => 8.25, + 'category' => 'services' +]; + +try { + $itemResponse = $businessGateway->eInvoiceService()->addInvoiceItem($invoiceId, $newItem); + + if ($itemResponse->isSuccessful()) { + echo "✓ Item added to invoice successfully\n"; + echo " Invoice ID: $invoiceId\n"; + echo " Item: {$newItem['description']}\n"; + echo " Price: $" . number_format($newItem['unit_price'], 2) . "\n"; + } else { + echo "✗ Error: " . $itemResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Send invoice to customer +echo "3. Sending invoice to customer\n"; +echo "------------------------------\n"; + +$sendParams = [ + 'method' => 'email', + 'email' => 'billing@acme.com', + 'subject' => 'Invoice ' . ($invoiceData['invoice_number'] ?? 'INV-2024-001234') . ' from Your Company', + 'message' => 'Dear Customer, please find attached your invoice. Payment is due within 30 days.', + 'copy_sender' => true, + 'attach_pdf' => true +]; + +try { + $sendResponse = $businessGateway->eInvoiceService()->sendInvoice($invoiceId, $sendParams); + + if ($sendResponse->isSuccessful()) { + echo "✓ Invoice sent successfully\n"; + echo " Invoice ID: $invoiceId\n"; + echo " Sent to: {$sendParams['email']}\n"; + echo " Method: {$sendParams['method']}\n"; + } else { + echo "✗ Error: " . $sendResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Download invoice PDF +echo "4. Downloading invoice PDF\n"; +echo "--------------------------\n"; + +$downloadOptions = [ + 'format' => 'pdf', + 'template' => 'professional', + 'include_payments' => true +]; + +try { + $downloadResponse = $businessGateway->eInvoiceService()->downloadInvoice($invoiceId, $downloadOptions); + + if ($downloadResponse->isSuccessful()) { + echo "✓ Invoice PDF ready for download\n"; + echo " Invoice ID: $invoiceId\n"; + echo " Format: PDF\n"; + echo " Template: Professional\n"; + echo " (In a real scenario, this would return the PDF data or download URL)\n"; + } else { + echo "✗ Error: " . $downloadResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} \ No newline at end of file diff --git a/code-samples/business/e-invoice/product.php b/code-samples/business/e-invoice/product.php new file mode 100644 index 0000000..6705b83 --- /dev/null +++ b/code-samples/business/e-invoice/product.php @@ -0,0 +1,333 @@ + '', + 'privateKey' => '', + 'isTest' => 1, +]); + +echo "FasterPay E-Invoice Product API Examples\n"; +echo "=========================================\n\n"; + +// Example 1: Create a digital product +echo "1. Creating a digital product\n"; +echo "-----------------------------\n"; + +$digitalProductData = [ + 'sku' => 'WEB-DEV-001', + 'type' => 'digital', + 'name' => 'Website Development Package', + 'description' => 'Complete website development with modern responsive design, SEO optimization, and content management system.', + 'prices' => [ + [ + 'price' => 2500.00, + 'currency' => 'USD' + ], + [ + 'price' => 2100.00, + 'currency' => 'EUR' + ] + ] +]; + +try { + $productResponse = $businessGateway->eInvoiceProductService()->createProduct($digitalProductData); + + if ($productResponse->isSuccessful()) { + echo "✓ Digital product created successfully\n"; + $responseData = $productResponse->getDecodeResponse(); + $productId = $responseData['data']['id'] ?? 'PD-' . time(); + echo " Product ID: $productId\n"; + echo " SKU: {$digitalProductData['sku']}\n"; + echo " Name: {$digitalProductData['name']}\n"; + echo " Type: {$digitalProductData['type']}\n"; + echo " Prices: \$2,500 USD / €2,100 EUR\n"; + echo " Image URL: " . ($responseData['data']['image_url'] ?? 'No image uploaded') . "\n"; + } else { + echo "✗ Error: " . $productResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 2: Create a physical product +echo "2. Creating a physical product\n"; +echo "------------------------------\n"; + +$physicalProductData = [ + 'sku' => 'LAPTOP-PRO-15', + 'type' => 'physical', + 'name' => 'Professional Laptop 15"', + 'description' => 'High-performance laptop with 16GB RAM, 512GB SSD, and professional graphics card. Perfect for developers and designers.', + 'prices' => [ + [ + 'price' => 1899.99, + 'currency' => 'USD' + ], + [ + 'price' => 1649.99, + 'currency' => 'EUR' + ], + [ + 'price' => 1499.99, + 'currency' => 'GBP' + ] + ] +]; + +try { + $laptopResponse = $businessGateway->eInvoiceProductService()->createProduct($physicalProductData); + + if ($laptopResponse->isSuccessful()) { + echo "✓ Physical product created successfully\n"; + $responseData = $laptopResponse->getDecodeResponse(); + $laptopId = $responseData['data']['id'] ?? 'PD-LAPTOP-' . time(); + echo " Product ID: $laptopId\n"; + echo " SKU: {$physicalProductData['sku']}\n"; + echo " Name: {$physicalProductData['name']}\n"; + echo " Type: {$physicalProductData['type']}\n"; + echo " Multi-currency pricing: USD/EUR/GBP\n"; + } else { + echo "✗ Error: " . $laptopResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Create a service product +echo "3. Creating a service product\n"; +echo "-----------------------------\n"; + +$serviceProductData = [ + 'sku' => 'CONSULT-HOUR', + 'type' => 'service', + 'name' => 'Technical Consulting Hour', + 'description' => 'One hour of expert technical consulting for software architecture, system design, and performance optimization.', + 'prices' => [ + [ + 'price' => 150.00, + 'currency' => 'USD' + ] + ] +]; + +try { + $consultingResponse = $businessGateway->eInvoiceProductService()->createProduct($serviceProductData); + + if ($consultingResponse->isSuccessful()) { + echo "✓ Service product created successfully\n"; + $responseData = $consultingResponse->getDecodeResponse(); + $consultingId = $responseData['data']['id'] ?? 'PD-CONSULT-' . time(); + echo " Product ID: $consultingId\n"; + echo " SKU: {$serviceProductData['sku']}\n"; + echo " Name: {$serviceProductData['name']}\n"; + echo " Type: {$serviceProductData['type']}\n"; + echo " Rate: \$150/hour\n"; + } else { + echo "✗ Error: " . $consultingResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Get product details +echo "4. Getting product details\n"; +echo "--------------------------\n"; + +$productId = $productId ?? 'PD-' . time(); + +try { + $detailsResponse = $businessGateway->eInvoiceProductService()->getProduct($productId); + + if ($detailsResponse->isSuccessful()) { + echo "✓ Product details retrieved\n"; + $details = $detailsResponse->getDecodeResponse(); + $product = $details['data'] ?? []; + + echo " ID: " . ($product['id'] ?? $productId) . "\n"; + echo " SKU: " . ($product['sku'] ?? 'N/A') . "\n"; + echo " Name: " . ($product['name'] ?? 'N/A') . "\n"; + echo " Type: " . ($product['type'] ?? 'N/A') . "\n"; + echo " Description: " . (substr($product['description'] ?? '', 0, 50) . '...') . "\n"; + + $prices = $product['prices'] ?? []; + if (!empty($prices)) { + echo " Prices: "; + foreach ($prices as $price) { + echo $price['currency'] . ' ' . $price['price'] . ' '; + } + echo "\n"; + } + } else { + echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 5: Update product +echo "5. Updating product\n"; +echo "-------------------\n"; + +$updateData = [ + 'description' => 'Updated: Premium website development package with advanced SEO, e-commerce integration, and 6 months support.', + 'prices' => [ + [ + 'price' => 2750.00, + 'currency' => 'USD' + ], + [ + 'price' => 2300.00, + 'currency' => 'EUR' + ] + ] +]; + +try { + $updateResponse = $businessGateway->eInvoiceProductService()->updateProduct($productId, $updateData); + + if ($updateResponse->isSuccessful()) { + echo "✓ Product updated successfully\n"; + echo " Updated pricing: \$2,750 USD / €2,300 EUR\n"; + echo " Updated description with enhanced features\n"; + } else { + echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: List all products +echo "6. Listing all products\n"; +echo "-----------------------\n"; + +try { + $listResponse = $businessGateway->eInvoiceProductService()->listProducts(); + + if ($listResponse->isSuccessful()) { + echo "✓ Product list retrieved\n"; + $listData = $listResponse->getDecodeResponse(); + $products = $listData['data']['data'] ?? []; + + echo " Total products: " . count($products) . "\n"; + + if (!empty($products)) { + echo " Product catalog:\n"; + foreach ($products as $product) { + $id = $product['id'] ?? 'Unknown'; + $sku = $product['sku'] ?? 'N/A'; + $name = $product['name'] ?? 'Unnamed'; + $type = $product['type'] ?? 'N/A'; + + echo " - $name (SKU: $sku, Type: $type, ID: $id)\n"; + } + } + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: Search product by SKU +echo "7. Searching product by SKU\n"; +echo "----------------------------\n"; + +try { + $skuResponse = $businessGateway->eInvoiceProductService()->getProductBySku('WEB-DEV-001'); + + if ($skuResponse->isSuccessful()) { + echo "✓ Product found by SKU\n"; + $skuData = $skuResponse->getDecodeResponse(); + $products = $skuData['data']['data'] ?? []; + + if (!empty($products)) { + $product = $products[0]; + echo " Found: " . ($product['name'] ?? 'Unknown') . "\n"; + echo " Type: " . ($product['type'] ?? 'N/A') . "\n"; + } + } else { + echo "✗ Error: " . $skuResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: Create a product bundle +echo "8. Creating product bundles\n"; +echo "---------------------------\n"; + +$bundleProducts = [ + [ + 'sku' => 'STARTUP-BUNDLE', + 'type' => 'digital', + 'name' => 'Startup Launch Bundle', + 'description' => 'Everything you need to launch your startup: website, logo design, business cards, and marketing materials.', + 'prices' => [ + [ + 'price' => 3999.00, + 'currency' => 'USD' + ] + ] + ], + [ + 'sku' => 'ENTERPRISE-PACKAGE', + 'type' => 'service', + 'name' => 'Enterprise Solution Package', + 'description' => 'Complete enterprise solution with custom development, integration, training, and 1-year support.', + 'prices' => [ + [ + 'price' => 25000.00, + 'currency' => 'USD' + ] + ] + ] +]; + +echo "Creating product bundles:\n"; + +foreach ($bundleProducts as $bundleData) { + try { + $response = $businessGateway->eInvoiceProductService()->createProduct($bundleData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $bundleId = $responseData['data']['id'] ?? 'PD-BUNDLE-' . time(); + $price = $bundleData['prices'][0]['price']; + $currency = $bundleData['prices'][0]['currency']; + + echo " ✓ {$bundleData['name']}: $" . number_format($price, 2) . " $currency (ID: $bundleId)\n"; + } else { + echo " ✗ Failed to create {$bundleData['name']}\n"; + } + } catch (FasterPay\Exception $e) { + echo " ✗ Exception creating {$bundleData['name']}: " . $e->getMessage() . "\n"; + } +} + +echo "\nE-Invoice Product API examples completed!\n"; +echo "Use cases:\n"; +echo "• Product catalog management\n"; +echo "• Multi-currency pricing\n"; +echo "• Service offering management\n"; +echo "• Digital product distribution\n"; +echo "• Physical inventory integration\n"; +echo "• Bundle and package creation\n"; +echo "• SKU-based product lookup\n"; +echo "• Dynamic pricing updates\n"; \ No newline at end of file diff --git a/code-samples/business/e-invoice/tax.php b/code-samples/business/e-invoice/tax.php new file mode 100644 index 0000000..ff31321 --- /dev/null +++ b/code-samples/business/e-invoice/tax.php @@ -0,0 +1,281 @@ + '', + 'privateKey' => '', + 'isTest' => 1, +]); + +echo "FasterPay E-Invoice Tax API Examples\n"; +echo "=====================================\n\n"; + +// Example 1: Create a flat tax +echo "1. Creating a flat tax\n"; +echo "----------------------\n"; + +$flatTaxData = [ + 'name' => 'Sales Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% flat sales tax rate' +]; + +try { + $taxResponse = $businessGateway->eInvoiceTaxService()->createTax($flatTaxData); + + if ($taxResponse->isSuccessful()) { + echo "✓ Flat tax created successfully\n"; + $responseData = $taxResponse->getDecodeResponse(); + $taxId = $responseData['data']['id'] ?? 'TX-' . time(); + echo " Tax ID: $taxId\n"; + echo " Name: {$flatTaxData['name']}\n"; + echo " Type: {$flatTaxData['type']}\n"; + echo " Rate: " . ($flatTaxData['value'] * 100) . "%\n"; + echo " Description: {$flatTaxData['description']}\n"; + } else { + echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 2: Create a percentage tax +echo "2. Creating a percentage tax\n"; +echo "----------------------------\n"; + +$percentageTaxData = [ + 'name' => 'VAT', + 'type' => 'percentage', + 'value' => 20, + 'description' => '20% Value Added Tax (UK)' +]; + +try { + $vatResponse = $businessGateway->eInvoiceTaxService()->createTax($percentageTaxData); + + if ($vatResponse->isSuccessful()) { + echo "✓ Percentage tax created successfully\n"; + $responseData = $vatResponse->getDecodeResponse(); + $vatId = $responseData['data']['id'] ?? 'TX-VAT-' . time(); + echo " Tax ID: $vatId\n"; + echo " Name: {$percentageTaxData['name']}\n"; + echo " Type: {$percentageTaxData['type']}\n"; + echo " Rate: {$percentageTaxData['value']}%\n"; + echo " Description: {$percentageTaxData['description']}\n"; + } else { + echo "✗ Error: " . $vatResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Create GST tax +echo "3. Creating GST tax\n"; +echo "-------------------\n"; + +$gstTaxData = [ + 'name' => 'GST', + 'type' => 'flat', + 'value' => 0.10, + 'description' => '10% Goods and Services Tax' +]; + +try { + $gstResponse = $businessGateway->eInvoiceTaxService()->createTax($gstTaxData); + + if ($gstResponse->isSuccessful()) { + echo "✓ GST tax created successfully\n"; + $responseData = $gstResponse->getDecodeResponse(); + $gstId = $responseData['data']['id'] ?? 'TX-GST-' . time(); + echo " Tax ID: $gstId\n"; + echo " Rate: " . ($gstTaxData['value'] * 100) . "% GST\n"; + } else { + echo "✗ Error: " . $gstResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Get tax details +echo "4. Getting tax details\n"; +echo "----------------------\n"; + +$taxId = $taxId ?? 'TX-' . time(); + +try { + $detailsResponse = $businessGateway->eInvoiceTaxService()->getTax($taxId); + + if ($detailsResponse->isSuccessful()) { + echo "✓ Tax details retrieved\n"; + $details = $detailsResponse->getDecodeResponse(); + $tax = $details['data'] ?? []; + + echo " ID: " . ($tax['id'] ?? $taxId) . "\n"; + echo " Name: " . ($tax['name'] ?? 'N/A') . "\n"; + echo " Type: " . ($tax['type'] ?? 'N/A') . "\n"; + echo " Value: " . ($tax['value'] ?? 'N/A') . "\n"; + echo " Description: " . ($tax['description'] ?? 'N/A') . "\n"; + } else { + echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 5: Update tax +echo "5. Updating tax\n"; +echo "---------------\n"; + +$updateData = [ + 'value' => 0.085, + 'description' => 'Updated to 8.5% sales tax rate' +]; + +try { + $updateResponse = $businessGateway->eInvoiceTaxService()->updateTax($taxId, $updateData); + + if ($updateResponse->isSuccessful()) { + echo "✓ Tax updated successfully\n"; + echo " New rate: " . ($updateData['value'] * 100) . "%\n"; + echo " Updated description: {$updateData['description']}\n"; + } else { + echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: List all taxes +echo "6. Listing all taxes\n"; +echo "--------------------\n"; + +try { + $listResponse = $businessGateway->eInvoiceTaxService()->listTaxes(); + + if ($listResponse->isSuccessful()) { + echo "✓ Tax list retrieved\n"; + $listData = $listResponse->getDecodeResponse(); + $taxes = $listData['data']['data'] ?? []; + + echo " Total taxes: " . count($taxes) . "\n"; + + if (!empty($taxes)) { + echo " Configured taxes:\n"; + foreach ($taxes as $tax) { + $id = $tax['id'] ?? 'Unknown'; + $name = $tax['name'] ?? 'Unnamed'; + $type = $tax['type'] ?? 'N/A'; + $value = $tax['value'] ?? 0; + + if ($type === 'percentage') { + echo " - $name ($id): $value% ($type)\n"; + } else { + echo " - $name ($id): " . ($value * 100) . "% ($type)\n"; + } + } + } + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: Create zero tax (tax-exempt) +echo "7. Creating tax-exempt option\n"; +echo "-----------------------------\n"; + +$zeroTaxData = [ + 'name' => 'Tax Exempt', + 'type' => 'flat', + 'value' => 0, + 'description' => 'No tax applied - tax exempt status' +]; + +try { + $zeroTaxResponse = $businessGateway->eInvoiceTaxService()->createTax($zeroTaxData); + + if ($zeroTaxResponse->isSuccessful()) { + echo "✓ Tax-exempt option created successfully\n"; + $responseData = $zeroTaxResponse->getDecodeResponse(); + $zeroTaxId = $responseData['data']['id'] ?? 'TX-EXEMPT-' . time(); + echo " Tax ID: $zeroTaxId\n"; + echo " Rate: 0% (tax exempt)\n"; + } else { + echo "✗ Error: " . $zeroTaxResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: Create multiple regional taxes +echo "8. Creating regional tax variations\n"; +echo "-----------------------------------\n"; + +$regionalTaxes = [ + [ + 'name' => 'California Sales Tax', + 'type' => 'flat', + 'value' => 0.0725, + 'description' => '7.25% California state sales tax' + ], + [ + 'name' => 'New York Sales Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% New York state sales tax' + ], + [ + 'name' => 'Texas Sales Tax', + 'type' => 'flat', + 'value' => 0.0625, + 'description' => '6.25% Texas state sales tax' + ] +]; + +$createdRegionalTaxes = []; + +foreach ($regionalTaxes as $taxData) { + try { + $response = $businessGateway->eInvoiceTaxService()->createTax($taxData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $taxId = $responseData['data']['id'] ?? 'TX-REGIONAL-' . time(); + $createdRegionalTaxes[] = $taxId; + + echo "✓ {$taxData['name']}: " . ($taxData['value'] * 100) . "% (ID: $taxId)\n"; + } else { + echo "✗ Failed to create {$taxData['name']}: " . $response->getErrors()->getMessage() . "\n"; + } + } catch (FasterPay\Exception $e) { + echo "✗ Exception creating {$taxData['name']}: " . $e->getMessage() . "\n"; + } +} + +echo " Created " . count($createdRegionalTaxes) . " regional tax configurations\n"; + +echo "\nE-Invoice Tax API examples completed!\n"; +echo "Use cases:\n"; +echo "• Multi-jurisdictional tax compliance\n"; +echo "• Automated tax calculation\n"; +echo "• Regional tax rate management\n"; +echo "• Tax-exempt transaction handling\n"; +echo "• VAT/GST compliance for international sales\n"; +echo "• Dynamic tax rate updates\n"; \ No newline at end of file diff --git a/code-samples/business/e-invoice/template.php b/code-samples/business/e-invoice/template.php new file mode 100644 index 0000000..19ddc5f --- /dev/null +++ b/code-samples/business/e-invoice/template.php @@ -0,0 +1,226 @@ + '', + 'privateKey' => '', + 'isTest' => 1, +]); + +echo "FasterPay E-Invoice Template API Examples\n"; +echo "==========================================\n\n"; + +// Example 1: Create a new invoice template +echo "1. Creating a new invoice template\n"; +echo "----------------------------------\n"; + +$templateData = [ + 'name' => 'Professional Template', + 'address' => null, + 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', + 'colors' => [ + 'primary' => '#2563eb', + 'secondary' => '#f8fafc' + ], + 'localized_address' => [ + 'address_line1' => '123 Business Avenue', + 'locality' => 'San Francisco', + 'administrative_area' => 'CA', + 'postal_code' => '94105' + ], + 'country_code' => 'US' +]; + +try { + $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); + + if ($templateResponse->isSuccessful()) { + echo "✓ Invoice template created successfully\n"; + $responseData = $templateResponse->getDecodeResponse(); + $templateId = $responseData['data']['id'] ?? 'IT-' . time(); + echo " Template ID: $templateId\n"; + echo " Name: {$templateData['name']}\n"; + echo " Primary Color: {$templateData['colors']['primary']}\n"; + echo " Address: {$templateData['localized_address']['address_line1']}, {$templateData['localized_address']['locality']}\n"; + echo " Full Address: " . ($responseData['data']['full_address'] ?? 'Generated automatically') . "\n"; + } else { + echo "✗ Error: " . $templateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 2: Create a template with custom branding +echo "2. Creating a branded template\n"; +echo "------------------------------\n"; + +$brandedTemplateData = [ + 'name' => 'Company Branded Template', + 'footer' => 'Powered by YourCompany © 2024 | www.yourcompany.com', + 'colors' => [ + 'primary' => '#ff6b35', + 'secondary' => '#f7f3f0' + ], + 'localized_address' => [ + 'address_line1' => '456 Corporate Blvd', + 'address_line2' => 'Suite 200', + 'locality' => 'New York', + 'administrative_area' => 'NY', + 'postal_code' => '10001' + ], + 'country_code' => 'US' +]; + +try { + $brandedResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($brandedTemplateData); + + if ($brandedResponse->isSuccessful()) { + echo "✓ Branded template created successfully\n"; + $responseData = $brandedResponse->getDecodeResponse(); + $brandedTemplateId = $responseData['data']['id'] ?? 'IT-BRAND-' . time(); + echo " Template ID: $brandedTemplateId\n"; + echo " Brand Colors: {$brandedTemplateData['colors']['primary']} / {$brandedTemplateData['colors']['secondary']}\n"; + echo " Corporate Address: {$brandedTemplateData['localized_address']['address_line1']}\n"; + } else { + echo "✗ Error: " . $brandedResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Get template details +echo "3. Getting template details\n"; +echo "---------------------------\n"; + +$templateId = $templateId ?? 'IT-' . time(); + +try { + $detailsResponse = $businessGateway->eInvoiceTemplateService()->getTemplate($templateId); + + if ($detailsResponse->isSuccessful()) { + echo "✓ Template details retrieved\n"; + $details = $detailsResponse->getDecodeResponse(); + $template = $details['data'] ?? []; + + echo " ID: " . ($template['id'] ?? $templateId) . "\n"; + echo " Name: " . ($template['name'] ?? 'N/A') . "\n"; + echo " Country: " . ($template['country_code'] ?? 'N/A') . "\n"; + echo " Footer: " . ($template['footer'] ?? 'N/A') . "\n"; + } else { + echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Update template +echo "4. Updating template\n"; +echo "--------------------\n"; + +$updateData = [ + 'footer' => 'Updated footer - Thank you for choosing our services!', + 'colors' => [ + 'primary' => '#059669', + 'secondary' => '#ecfdf5' + ] +]; + +try { + $updateResponse = $businessGateway->eInvoiceTemplateService()->updateTemplate($templateId, $updateData); + + if ($updateResponse->isSuccessful()) { + echo "✓ Template updated successfully\n"; + echo " Updated primary color to: {$updateData['colors']['primary']}\n"; + echo " Updated footer\n"; + } else { + echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 5: List all templates +echo "5. Listing all templates\n"; +echo "------------------------\n"; + +try { + $listResponse = $businessGateway->eInvoiceTemplateService()->listTemplates(); + + if ($listResponse->isSuccessful()) { + echo "✓ Templates list retrieved\n"; + $listData = $listResponse->getDecodeResponse(); + $templates = $listData['data']['data'] ?? []; + + echo " Total templates: " . count($templates) . "\n"; + + if (!empty($templates)) { + echo " Templates:\n"; + foreach ($templates as $template) { + $id = $template['id'] ?? 'Unknown'; + $name = $template['name'] ?? 'Unnamed'; + $country = $template['country_code'] ?? 'N/A'; + echo " - $name ($id) - Country: $country\n"; + } + } + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: Create template for different country +echo "6. Creating template for UK\n"; +echo "---------------------------\n"; + +$ukTemplateData = [ + 'name' => 'UK Template', + 'footer' => 'Registered in England and Wales', + 'colors' => [ + 'primary' => '#1e40af', + 'secondary' => '#eff6ff' + ], + 'localized_address' => [ + 'address_line1' => '10 Downing Street', + 'locality' => 'London', + 'postal_code' => 'SW1A 2AA' + ], + 'country_code' => 'GB' +]; + +try { + $ukResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($ukTemplateData); + + if ($ukResponse->isSuccessful()) { + echo "✓ UK template created successfully\n"; + $responseData = $ukResponse->getDecodeResponse(); + $ukTemplateId = $responseData['data']['id'] ?? 'IT-UK-' . time(); + echo " Template ID: $ukTemplateId\n"; + echo " Country: GB (United Kingdom)\n"; + echo " Address format: UK postal code format\n"; + } else { + echo "✗ Error: " . $ukResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\nE-Invoice Template API examples completed!\n"; +echo "Use cases:\n"; +echo "• Brand-consistent invoice design\n"; +echo "• Multi-country invoice templates\n"; +echo "• Corporate identity management\n"; +echo "• Professional invoice presentation\n"; +echo "• Template reuse across invoices\n"; +echo "• Localized address formatting\n"; \ No newline at end of file diff --git a/code-samples/business/payout.php b/code-samples/business/payout.php new file mode 100644 index 0000000..3ece328 --- /dev/null +++ b/code-samples/business/payout.php @@ -0,0 +1,145 @@ + '', + 'privateKey' => '', + 'isTest' => 1, +]); + +// Example 1: Create mass payout +$massPayoutParams = [ + 'source_currency' => 'USD', + 'template' => 'wallet', + 'payouts' => [ + [ + 'reference_id' => 'payout_001', + 'amount' => '150.00', + 'amount_currency' => 'USD', + 'target_currency' => 'USD', + 'receiver_full_name' => 'John Doe', + 'receiver_email' => 'john@example.com', + 'receiver_type' => 'private' + ], + [ + 'reference_id' => 'payout_002', + 'amount' => '75.50', + 'amount_currency' => 'USD', + 'target_currency' => 'USD', + 'receiver_full_name' => 'Jane Smith', + 'receiver_email' => 'jane@example.com', + 'receiver_type' => 'private' + ], + [ + 'reference_id' => 'payout_003', + 'amount' => '200.25', + 'amount_currency' => 'USD', + 'target_currency' => 'USD', + 'receiver_full_name' => 'Bob Johnson', + 'receiver_email' => 'bob@example.com', + 'receiver_type' => 'business' + ] + ] +]; + +try { + $massPayoutResponse = $businessGateway->massPayoutService()->createPayout($massPayoutParams); + + if ($massPayoutResponse->isSuccessful()) { + echo "Mass payout created successfully\n"; + echo "Response: " . $massPayoutResponse->getRawResponse() . "\n"; + + // Extract payout ID from response for further operations + $responseData = $massPayoutResponse->getDecodeResponse(); + $payoutId = $responseData['payout_id'] ?? null; + + if ($payoutId) { + echo "Payout ID: " . $payoutId . "\n"; + } + } else { + echo "Error: " . $massPayoutResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +// Example 2: Get payout details +$payoutId = ''; + +try { + $payoutDetails = $businessGateway->massPayoutService()->getPayoutDetails($payoutId); + + if ($payoutDetails->isSuccessful()) { + echo "Payout details retrieved successfully\n"; + echo "Details: " . $payoutDetails->getRawResponse() . "\n"; + } else { + echo "Error: " . $payoutDetails->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +// Example 3: Get payout list with filters +$filters = [ + 'limit' => 20, + 'offset' => 0, + 'status' => 'pending', + 'from_date' => '2024-01-01', + 'to_date' => '2024-12-31' +]; + +try { + $payoutList = $businessGateway->massPayoutService()->getPayoutList($filters); + + if ($payoutList->isSuccessful()) { + echo "Payout list retrieved successfully\n"; + echo "List: " . $payoutList->getRawResponse() . "\n"; + } else { + echo "Error: " . $payoutList->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +// Example 4: Get payout status +try { + $payoutStatus = $businessGateway->massPayoutService()->getPayoutStatus($payoutId); + + if ($payoutStatus->isSuccessful()) { + echo "Payout status retrieved successfully\n"; + echo "Status: " . $payoutStatus->getRawResponse() . "\n"; + } else { + echo "Error: " . $payoutStatus->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +// Example 5: Cancel payout (if still pending) +try { + $cancelResponse = $businessGateway->massPayoutService()->cancelPayout($payoutId); + + if ($cancelResponse->isSuccessful()) { + echo "Payout cancelled successfully\n"; + echo "Response: " . $cancelResponse->getRawResponse() . "\n"; + } else { + echo "Error: " . $cancelResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +// Example 6: Retry failed payout +try { + $retryResponse = $businessGateway->massPayoutService()->retryPayout($payoutId); + + if ($retryResponse->isSuccessful()) { + echo "Payout retry initiated successfully\n"; + echo "Response: " . $retryResponse->getRawResponse() . "\n"; + } else { + echo "Error: " . $retryResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} \ No newline at end of file diff --git a/lib/FasterPay/BusinessGateway.php b/lib/FasterPay/BusinessGateway.php new file mode 100644 index 0000000..77ef431 --- /dev/null +++ b/lib/FasterPay/BusinessGateway.php @@ -0,0 +1,172 @@ +config = $config; + + // Override the base URL for business APIs + if ($this->config->getIsTest()) { + $this->config->setBaseUrl(self::BUSINESS_API_SANDBOX_BASE_URL); + } else { + $this->config->setBaseUrl(self::BUSINESS_API_BASE_URL); + } + + $header = [ + 'X-ApiKey: ' . $this->config->getPrivateKey(), + 'Content-Type: application/json' + ]; + + $this->http = new HttpClient($header); + } + + protected function getBaseUrl() + { + if (!$url = $this->config->getApiBaseUrl()) { + $url = $this->baseUrl; + } + + return $url . '/'; + } + + public function getEndPoint($endpoint) + { + return $this->getBaseUrl() . $endpoint; + } + + public function getHttpClient() + { + return $this->http; + } + + public function signature() + { + return new Signature($this); + } + + public function pingback() + { + return new Pingback($this); + } + + /** + * Mass Payout Service + * + * @return Payout + */ + public function payoutService() + { + return new Payout(new HttpService($this)); + } + + /** + * Address Service + * + * @return Address + */ + public function addressService() + { + return new Address(new HttpService($this)); + } + + /** + * Contact Service + * + * @return Contact + */ + public function contactService() + { + return new Contact(new HttpService($this)); + } + + /** + * Invoice Service + * + * @return Invoice + */ + public function invoiceService() + { + return new Invoice(new HttpService($this)); + } + + /** + * Invoice Template Service + * + * @return Template + */ + public function invoiceTemplateService() + { + return new Template(new HttpService($this)); + } + + /** + * Invoice Tax Service + * + * @return Tax + */ + public function invoiceTaxService() + { + return new Tax(new HttpService($this)); + } + + /** + * Invoice Discount Service + * + * @return Discount + */ + public function invoiceDiscountService() + { + return new Discount(new HttpService($this)); + } + + /** + * Invoice Product Service + * + * @return Product + */ + public function invoiceProductService() + { + return new Product(new HttpService($this)); + } + + public function getConfig() + { + return $this->config; + } + + public function callApi($endpoint, array $payload, $method = GenericApiService::HTTP_METHOD_POST, $header = []) + { + $endpoint = $this->getEndPoint($endpoint); + + $service = new GenericApiService(new HttpClient); + return $service->call($endpoint, $payload, $method, $header); + } +} \ No newline at end of file diff --git a/lib/FasterPay/Gateway.php b/lib/FasterPay/Gateway.php index 54419fe..4387369 100644 --- a/lib/FasterPay/Gateway.php +++ b/lib/FasterPay/Gateway.php @@ -10,14 +10,12 @@ use FasterPay\Services\Signature; use FasterPay\Services\Pingback; -class Gateway +class Gateway implements GatewayInterface { protected $config; protected $http; protected $baseUrl = ''; - protected $project; - protected $extraParams = []; public function __construct($config = []) { diff --git a/lib/FasterPay/GatewayInterface.php b/lib/FasterPay/GatewayInterface.php new file mode 100644 index 0000000..e52278e --- /dev/null +++ b/lib/FasterPay/GatewayInterface.php @@ -0,0 +1,14 @@ + $response, 'httpCode' => $info['http_code'] - ); + ]; } } diff --git a/lib/FasterPay/Response/PaymentResponse.php b/lib/FasterPay/Response/PaymentResponse.php index 9f97dbd..90d2030 100644 --- a/lib/FasterPay/Response/PaymentResponse.php +++ b/lib/FasterPay/Response/PaymentResponse.php @@ -13,7 +13,10 @@ public function handleResult() if ($httpCode != self::SUCCESS_CODE) { $errorMessage = empty($response['message']) ? self::RESPONSE_ERROR_TEXT : $response['message']; - $this->errors = new ResponseError(array('message' => $errorMessage, 'code' => $httpCode)); + $this->errors = new ResponseError([ + 'message' => $errorMessage, + 'code' => $httpCode, + ]); } else { $this->success = true; } diff --git a/lib/FasterPay/Response/SubscriptionResponse.php b/lib/FasterPay/Response/SubscriptionResponse.php index 6d9064b..c67aa31 100644 --- a/lib/FasterPay/Response/SubscriptionResponse.php +++ b/lib/FasterPay/Response/SubscriptionResponse.php @@ -14,7 +14,10 @@ public function handleResult() } elseif (!empty($response['type']) && $response['type'] == self::RESPONSE_ERROR_TEXT) { $errorMessage = empty($response['message']) ? 'Error' : $response['message']; $code = empty($response['code']) ? self::DEFAULT_ERROR_CODE : $response['code']; - $this->errors = new ResponseError(array('message' => $errorMessage, 'code' => $code)); + $this->errors = new ResponseError([ + 'message' => $errorMessage, + 'code' => $code, + ]); } } diff --git a/lib/FasterPay/Services/Business/Address.php b/lib/FasterPay/Services/Business/Address.php new file mode 100644 index 0000000..49fc0ce --- /dev/null +++ b/lib/FasterPay/Services/Business/Address.php @@ -0,0 +1,254 @@ +httpService->getEndPoint($this->endpoint . '/fields/' . strtoupper($countryCode)); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Get supported address fields for multiple countries + * + * @param array $countryCodes Array of country codes + * @return array Array of GeneralResponse objects keyed by country code + * @throws Exception + */ + public function getMultipleAddressFields(array $countryCodes = []) + { + if (empty($countryCodes)) { + throw new Exception('At least one country code is required'); + } + + $responses = []; + + foreach ($countryCodes as $countryCode) { + try { + $responses[$countryCode] = $this->getAddressFields($countryCode); + } catch (Exception $e) { + // Log error but continue with other countries + error_log("Error getting address fields for $countryCode: " . $e->getMessage()); + $responses[$countryCode] = null; + } + } + + return $responses; + } + + /** + * Get subdivisions (states/provinces) for a country + * + * @param string $countryCode Country code (ISO 2-letter) + * @return array Array of subdivisions + * @throws Exception + */ + public function getSubdivisions($countryCode = '') + { + $fieldsResponse = $this->getAddressFields($countryCode); + + if ($fieldsResponse->isSuccessful()) { + $data = $fieldsResponse->getDecodeResponse(); + return $data['data']['subdivisions'] ?? []; + } + + return []; + } + + /** + * Get required fields for a country + * + * @param string $countryCode Country code (ISO 2-letter) + * @return array Array of required field definitions + * @throws Exception + */ + public function getRequiredFields($countryCode = '') + { + $fieldsResponse = $this->getAddressFields($countryCode); + + if ($fieldsResponse->isSuccessful()) { + $data = $fieldsResponse->getDecodeResponse(); + return $data['data']['fields'] ?? []; + } + + return []; + } + + /** + * Validate address data against country requirements + * + * @param array $addressData Address data to validate + * @param string $countryCode Country code for validation rules + * @return array Validation results + * @throws Exception + */ + public function validateAddressData(array $addressData = [], $countryCode = '') + { + if (empty($countryCode)) { + throw new Exception('Country code is required for validation'); + } + + $requiredFields = $this->getRequiredFields($countryCode); + $validationErrors = []; + $validationWarnings = []; + + foreach ($requiredFields as $field) { + $fieldName = $field['name'] ?? ''; + $fieldLabel = $field['label'] ?? $fieldName; + $fieldType = $field['type'] ?? 'text'; + + // Check if required field is present + if (empty($addressData[$fieldName])) { + $validationErrors[] = "$fieldLabel is required for $countryCode"; + continue; + } + + // Validate field type + switch ($fieldType) { + case 'select': + // For select fields, validate against subdivisions + if ($fieldName === 'administrative_area') { + $subdivisions = $this->getSubdivisions($countryCode); + $validCodes = array_column($subdivisions, 'code'); + + if (!in_array($addressData[$fieldName], $validCodes)) { + $validationErrors[] = "Invalid $fieldLabel for $countryCode"; + } + } + break; + + case 'text': + // Basic text validation + if (strlen($addressData[$fieldName]) < 2) { + $validationWarnings[] = "$fieldLabel seems too short"; + } + break; + } + } + + return [ + 'valid' => empty($validationErrors), + 'errors' => $validationErrors, + 'warnings' => $validationWarnings, + 'country_code' => $countryCode + ]; + } + + /** + * Get address format template for a country + * + * @param string $countryCode Country code (ISO 2-letter) + * @return array Address format information + * @throws Exception + */ + public function getAddressFormat($countryCode = '') + { + $fieldsResponse = $this->getAddressFields($countryCode); + + if ($fieldsResponse->isSuccessful()) { + $data = $fieldsResponse->getDecodeResponse(); + $fields = $data['data']['fields'] ?? []; + + return [ + 'country_code' => $countryCode, + 'fields' => $fields, + 'field_order' => array_column($fields, 'name'), + 'required_fields' => array_column($fields, 'name'), + 'subdivisions_available' => !empty($data['data']['subdivisions']) + ]; + } + + throw new Exception("Could not retrieve address format for $countryCode"); + } + + /** + * Check if a country supports subdivisions (states/provinces) + * + * @param string $countryCode Country code (ISO 2-letter) + * @return bool True if country has subdivisions + * @throws Exception + */ + public function hasSubdivisions($countryCode = '') + { + $subdivisions = $this->getSubdivisions($countryCode); + return !empty($subdivisions); + } + + /** + * Get subdivision by code + * + * @param string $countryCode Country code (ISO 2-letter) + * @param string $subdivisionCode Subdivision code + * @return array|null Subdivision information or null if not found + * @throws Exception + */ + public function getSubdivisionByCode($countryCode = '', $subdivisionCode = '') + { + if (empty($subdivisionCode)) { + throw new Exception('Subdivision code is required'); + } + + $subdivisions = $this->getSubdivisions($countryCode); + + foreach ($subdivisions as $subdivision) { + if ($subdivision['code'] === $subdivisionCode) { + return $subdivision; + } + } + + return null; + } + + /** + * Search subdivisions by name + * + * @param string $countryCode Country code (ISO 2-letter) + * @param string $searchTerm Search term + * @return array Array of matching subdivisions + * @throws Exception + */ + public function searchSubdivisions($countryCode = '', $searchTerm = '') + { + if (empty($searchTerm)) { + throw new Exception('Search term is required'); + } + + $subdivisions = $this->getSubdivisions($countryCode); + $matches = []; + + foreach ($subdivisions as $subdivision) { + if (stripos($subdivision['name'], $searchTerm) !== false || + stripos($subdivision['code'], $searchTerm) !== false) { + $matches[] = $subdivision; + } + } + + return $matches; + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/Contact.php b/lib/FasterPay/Services/Business/Contact.php new file mode 100644 index 0000000..4e04a7e --- /dev/null +++ b/lib/FasterPay/Services/Business/Contact.php @@ -0,0 +1,311 @@ +validateContactParams($params); + + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->post($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Get contact details + * + * @param string $contactId Contact ID + * @return GeneralResponse + * @throws Exception + */ + public function getContact($contactId = '') + { + if (empty($contactId)) { + throw new Exception('Contact ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Update contact + * + * @param string $contactId Contact ID + * @param array $params Updated contact parameters + * @return GeneralResponse + * @throws Exception + */ + public function updateContact($contactId = '', array $params = []) + { + if (empty($contactId)) { + throw new Exception('Contact ID is required'); + } + + $this->validateContactParams($params, false); + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Delete contact + * + * @param string $contactId Contact ID + * @return GeneralResponse + * @throws Exception + */ + public function deleteContact($contactId = '') + { + if (empty($contactId)) { + throw new Exception('Contact ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId); + + $response = $this->httpService->getHttpClient()->delete($endpoint); + + return new GeneralResponse($response); + } + + /** + * List contacts + * + * @param array $filters Optional filters (limit, offset, type, status, etc.) + * @return GeneralResponse + */ + public function listContacts(array $filters = []) + { + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->get($endpoint, $filters); + + return new GeneralResponse($response); + } + + /** + * Search contacts + * + * @param array $searchParams Search parameters (name, email, phone, etc.) + * @return GeneralResponse + * @throws Exception + */ + public function searchContacts(array $searchParams = []) + { + if (empty($searchParams)) { + throw new Exception('Search parameters are required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/search'); + + $response = $this->httpService->getHttpClient()->post($endpoint, $searchParams); + + return new GeneralResponse($response); + } + + /** + * Get contact by email + * + * @param string $email Email address + * @return GeneralResponse + * @throws Exception + */ + public function getContactByEmail($email = '') + { + if (empty($email)) { + throw new Exception('Email address is required'); + } + + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + throw new Exception('Invalid email format'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/email/' . urlencode($email)); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Get contact by phone + * + * @param string $phone Phone number + * @return GeneralResponse + * @throws Exception + */ + public function getContactByPhone($phone = '') + { + if (empty($phone)) { + throw new Exception('Phone number is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/phone/' . urlencode($phone)); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Add address to contact + * + * @param string $contactId Contact ID + * @param array $addressData Address data + * @return GeneralResponse + * @throws Exception + */ + public function addContactAddress($contactId = '', array $addressData = []) + { + if (empty($contactId)) { + throw new Exception('Contact ID is required'); + } + + if (empty($addressData)) { + throw new Exception('Address data is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId . '/address'); + + $response = $this->httpService->getHttpClient()->post($endpoint, $addressData); + + return new GeneralResponse($response); + } + + /** + * Update contact address + * + * @param string $contactId Contact ID + * @param string $addressId Address ID + * @param array $addressData Updated address data + * @return GeneralResponse + * @throws Exception + */ + public function updateContactAddress($contactId = '', $addressId = '', array $addressData = []) + { + if (empty($contactId)) { + throw new Exception('Contact ID is required'); + } + + if (empty($addressId)) { + throw new Exception('Address ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId . '/address/' . $addressId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $addressData); + + return new GeneralResponse($response); + } + + /** + * Remove address from contact + * + * @param string $contactId Contact ID + * @param string $addressId Address ID + * @return GeneralResponse + * @throws Exception + */ + public function removeContactAddress($contactId = '', $addressId = '') + { + if (empty($contactId)) { + throw new Exception('Contact ID is required'); + } + + if (empty($addressId)) { + throw new Exception('Address ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId . '/address/' . $addressId); + + $response = $this->httpService->getHttpClient()->delete($endpoint); + + return new GeneralResponse($response); + } + + /** + * Get contact addresses + * + * @param string $contactId Contact ID + * @return GeneralResponse + * @throws Exception + */ + public function getContactAddresses($contactId = '') + { + if (empty($contactId)) { + throw new Exception('Contact ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId . '/addresses'); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Validate contact parameters + * + * @param array $params Contact parameters + * @param bool $requireAll Whether all fields are required (for create vs update) + * @throws Exception + */ + private function validateContactParams(array $params, $requireAll = true) + { + if ($requireAll) { + if (empty($params['first_name']) && empty($params['name'])) { + throw new Exception('First name or name is required'); + } + + if (empty($params['email']) && empty($params['phone'])) { + throw new Exception('Email or phone number is required'); + } + } + + // Validate email format if provided + if (!empty($params['email']) && !filter_var($params['email'], FILTER_VALIDATE_EMAIL)) { + throw new Exception('Invalid email format'); + } + + // Validate phone format if provided (basic validation) + if (!empty($params['phone'])) { + $phone = preg_replace('/[^\d+]/', '', $params['phone']); + if (strlen($phone) < 7 || strlen($phone) > 15) { + throw new Exception('Invalid phone number format'); + } + } + + // Validate phone_country_code if provided + if (!empty($params['phone_country_code']) && strlen($params['phone_country_code']) !== 2) { + throw new Exception('Phone country code must be 2 characters (ISO 3166-1 alpha-2)'); + } + + // Validate country if provided + if (!empty($params['country']) && strlen($params['country']) !== 2) { + throw new Exception('Country must be 2 characters (ISO 3166-1 alpha-2)'); + } + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Discount.php b/lib/FasterPay/Services/Business/EInvoice/Discount.php new file mode 100644 index 0000000..a84f891 --- /dev/null +++ b/lib/FasterPay/Services/Business/EInvoice/Discount.php @@ -0,0 +1,170 @@ + 100)) { + throw new Exception('Percentage discount value must be between 0 and 100'); + } + + if ($params['type'] === 'flat' && $params['value'] < 0) { + throw new Exception('Flat discount value must be non-negative'); + } + + // Validate currency for flat discounts + if ($params['type'] === 'flat' && empty($params['currency'])) { + throw new Exception('Currency is required for flat discount type'); + } + + if (!empty($params['currency']) && strlen($params['currency']) !== 3) { + throw new Exception('Currency must be 3 characters (ISO 4217)'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->post($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Get discount details + * + * @param string $discountId Discount ID + * @return GeneralResponse + * @throws Exception + */ + public function getDiscount($discountId = '') + { + if (empty($discountId)) { + throw new Exception('Discount ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $discountId); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Update discount + * + * @param string $discountId Discount ID + * @param array $params Updated discount parameters + * @return GeneralResponse + * @throws Exception + */ + public function updateDiscount($discountId = '', array $params = []) + { + if (empty($discountId)) { + throw new Exception('Discount ID is required'); + } + + // Validate discount type if provided + if (!empty($params['type'])) { + $validTypes = ['flat', 'percentage']; + if (!in_array($params['type'], $validTypes)) { + throw new Exception('Discount type must be either "flat" or "percentage"'); + } + } + + // Validate value if provided + if (isset($params['value'])) { + if (!is_numeric($params['value'])) { + throw new Exception('Discount value must be numeric'); + } + + if (!empty($params['type'])) { + if ($params['type'] === 'percentage' && ($params['value'] < 0 || $params['value'] > 100)) { + throw new Exception('Percentage discount value must be between 0 and 100'); + } + + if ($params['type'] === 'flat' && $params['value'] < 0) { + throw new Exception('Flat discount value must be non-negative'); + } + } + } + + // Validate currency if provided + if (!empty($params['currency']) && strlen($params['currency']) !== 3) { + throw new Exception('Currency must be 3 characters (ISO 4217)'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $discountId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Delete discount + * + * @param string $discountId Discount ID + * @return GeneralResponse + * @throws Exception + */ + public function deleteDiscount($discountId = '') + { + if (empty($discountId)) { + throw new Exception('Discount ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $discountId); + + $response = $this->httpService->getHttpClient()->delete($endpoint); + + return new GeneralResponse($response); + } + + /** + * List discounts + * + * @param array $filters Optional filters + * @return GeneralResponse + */ + public function listDiscounts(array $filters = []) + { + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->get($endpoint, $filters); + + return new GeneralResponse($response); + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Invoice.php b/lib/FasterPay/Services/Business/EInvoice/Invoice.php new file mode 100644 index 0000000..b58506f --- /dev/null +++ b/lib/FasterPay/Services/Business/EInvoice/Invoice.php @@ -0,0 +1,433 @@ +httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->post($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Get e-invoice details + * + * @param string $invoiceId Invoice ID + * @return GeneralResponse + * @throws Exception + */ + public function getInvoice($invoiceId = '') + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Update e-invoice + * + * @param string $invoiceId Invoice ID + * @param array $params Updated invoice parameters + * @return GeneralResponse + * @throws Exception + */ + public function updateInvoice($invoiceId = '', array $params = []) + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + $this->validateInvoiceParams($params, false); + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Delete e-invoice + * + * @param string $invoiceId Invoice ID + * @return GeneralResponse + * @throws Exception + */ + public function deleteInvoice($invoiceId = '') + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId); + + $response = $this->httpService->getHttpClient()->delete($endpoint); + + return new GeneralResponse($response); + } + + /** + * List e-invoices + * + * @param array $filters Optional filters (limit, offset, status, date_from, date_to, etc.) + * @return GeneralResponse + */ + public function listInvoices(array $filters = []) + { + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->get($endpoint, $filters); + + return new GeneralResponse($response); + } + + /** + * Send e-invoice + * + * @param string $invoiceId Invoice ID + * @param array $sendParams Send parameters (email, method, etc.) + * @return GeneralResponse + * @throws Exception + */ + public function sendInvoice($invoiceId = '', array $sendParams = []) + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/send'); + + $response = $this->httpService->getHttpClient()->post($endpoint, $sendParams); + + return new GeneralResponse($response); + } + + /** + * Download e-invoice PDF + * + * @param string $invoiceId Invoice ID + * @param array $options Download options (format, template, etc.) + * @return GeneralResponse + * @throws Exception + */ + public function downloadInvoice($invoiceId = '', array $options = []) + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/download'); + + $response = $this->httpService->getHttpClient()->get($endpoint, $options); + + return new GeneralResponse($response); + } + + /** + * Get invoice status + * + * @param string $invoiceId Invoice ID + * @return GeneralResponse + * @throws Exception + */ + public function getInvoiceStatus($invoiceId = '') + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/status'); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Cancel e-invoice + * + * @param string $invoiceId Invoice ID + * @param array $cancelParams Cancellation parameters (reason, etc.) + * @return GeneralResponse + * @throws Exception + */ + public function cancelInvoice($invoiceId = '', array $cancelParams = []) + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/cancel'); + + $response = $this->httpService->getHttpClient()->post($endpoint, $cancelParams); + + return new GeneralResponse($response); + } + + /** + * Mark invoice as paid + * + * @param string $invoiceId Invoice ID + * @param array $paymentData Payment data (amount, date, method, etc.) + * @return GeneralResponse + * @throws Exception + */ + public function markAsPaid($invoiceId = '', array $paymentData = []) + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + if (empty($paymentData['amount'])) { + throw new Exception('Payment amount is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/paid'); + + $response = $this->httpService->getHttpClient()->post($endpoint, $paymentData); + + return new GeneralResponse($response); + } + + /** + * Add item to invoice + * + * @param string $invoiceId Invoice ID + * @param array $itemData Item data + * @return GeneralResponse + * @throws Exception + */ + public function addInvoiceItem($invoiceId = '', array $itemData = []) + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + $this->validateInvoiceItem($itemData); + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/items'); + + $response = $this->httpService->getHttpClient()->post($endpoint, $itemData); + + return new GeneralResponse($response); + } + + /** + * Update invoice item + * + * @param string $invoiceId Invoice ID + * @param string $itemId Item ID + * @param array $itemData Updated item data + * @return GeneralResponse + * @throws Exception + */ + public function updateInvoiceItem($invoiceId = '', $itemId = '', array $itemData = []) + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + if (empty($itemId)) { + throw new Exception('Item ID is required'); + } + + $this->validateInvoiceItem($itemData, false); + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/items/' . $itemId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $itemData); + + return new GeneralResponse($response); + } + + /** + * Remove item from invoice + * + * @param string $invoiceId Invoice ID + * @param string $itemId Item ID + * @return GeneralResponse + * @throws Exception + */ + public function removeInvoiceItem($invoiceId = '', $itemId = '') + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + + if (empty($itemId)) { + throw new Exception('Item ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/items/' . $itemId); + + $response = $this->httpService->getHttpClient()->delete($endpoint); + + return new GeneralResponse($response); + } + + /** + * Search invoices + * + * @param array $searchParams Search parameters + * @return GeneralResponse + * @throws Exception + */ + public function searchInvoices(array $searchParams = []) + { + if (empty($searchParams)) { + throw new Exception('Search parameters are required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/search'); + + $response = $this->httpService->getHttpClient()->post($endpoint, $searchParams); + + return new GeneralResponse($response); + } + + /** + * Validate invoice parameters + * + * @param array $params Invoice parameters + * @param bool $requireAll Whether all fields are required (for create vs update) + * @throws Exception + */ + private function validateInvoiceParams(array $params, $requireAll = true) + { + if ($requireAll) { + if (empty($params['customer_id']) && empty($params['customer'])) { + throw new Exception('Customer ID or customer details are required'); + } + + if (empty($params['items']) || !is_array($params['items'])) { + throw new Exception('Invoice items are required'); + } + + if (empty($params['due_date'])) { + throw new Exception('Due date is required'); + } + } + + // Validate due date format if provided + if (!empty($params['due_date'])) { + $date = \DateTime::createFromFormat('Y-m-d', $params['due_date']); + if (!$date || $date->format('Y-m-d') !== $params['due_date']) { + throw new Exception('Invalid due date format. Use YYYY-MM-DD'); + } + } + + // Validate currency if provided + if (!empty($params['currency']) && strlen($params['currency']) !== 3) { + throw new Exception('Currency must be 3 characters (ISO 4217)'); + } + + // Validate status if provided + if (!empty($params['status'])) { + $validStatuses = ['draft', 'sent', 'paid', 'cancelled', 'overdue']; + if (!in_array($params['status'], $validStatuses)) { + throw new Exception('Invalid status. Must be one of: ' . implode(', ', $validStatuses)); + } + } + + // Validate items if provided + if (!empty($params['items']) && is_array($params['items'])) { + foreach ($params['items'] as $item) { + $this->validateInvoiceItem($item); + } + } + } + + /** + * Validate invoice item + * + * @param array $item Item data + * @param bool $requireAll Whether all fields are required + * @throws Exception + */ + private function validateInvoiceItem(array $item, $requireAll = true) + { + if ($requireAll) { + if (empty($item['description'])) { + throw new Exception('Item description is required'); + } + + if (empty($item['quantity']) || !is_numeric($item['quantity'])) { + throw new Exception('Item quantity is required and must be numeric'); + } + + if (empty($item['unit_price']) || !is_numeric($item['unit_price'])) { + throw new Exception('Item unit price is required and must be numeric'); + } + } + + // Validate quantity if provided + if (!empty($item['quantity']) && (!is_numeric($item['quantity']) || $item['quantity'] <= 0)) { + throw new Exception('Item quantity must be a positive number'); + } + + // Validate unit price if provided + if (!empty($item['unit_price']) && (!is_numeric($item['unit_price']) || $item['unit_price'] < 0)) { + throw new Exception('Item unit price must be a non-negative number'); + } + + // Validate tax rate if provided + if (!empty($item['tax_rate']) && (!is_numeric($item['tax_rate']) || $item['tax_rate'] < 0 || $item['tax_rate'] > 100)) { + throw new Exception('Item tax rate must be between 0 and 100'); + } + + // Validate discount if provided + if (!empty($item['discount']) && (!is_numeric($item['discount']) || $item['discount'] < 0)) { + throw new Exception('Item discount must be a non-negative number'); + } + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Product.php b/lib/FasterPay/Services/Business/EInvoice/Product.php new file mode 100644 index 0000000..a11d1a2 --- /dev/null +++ b/lib/FasterPay/Services/Business/EInvoice/Product.php @@ -0,0 +1,181 @@ +httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->post($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Get product details + * + * @param string $productId Product ID + * @return GeneralResponse + * @throws Exception + */ + public function getProduct($productId = '') + { + if (empty($productId)) { + throw new Exception('Product ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $productId); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Update product + * + * @param string $productId Product ID + * @param array $params Updated product parameters + * @return GeneralResponse + * @throws Exception + */ + public function updateProduct($productId = '', array $params = []) + { + if (empty($productId)) { + throw new Exception('Product ID is required'); + } + + // Validate product type if provided + if (!empty($params['type'])) { + $validTypes = ['digital', 'physical', 'service']; + if (!in_array($params['type'], $validTypes)) { + throw new Exception('Product type must be one of: ' . implode(', ', $validTypes)); + } + } + + // Validate prices if provided + if (!empty($params['prices']) && is_array($params['prices'])) { + foreach ($params['prices'] as $price) { + if (!isset($price['price']) || !is_numeric($price['price'])) { + throw new Exception('Each price must have a numeric price value'); + } + if (empty($price['currency']) || strlen($price['currency']) !== 3) { + throw new Exception('Each price must have a valid 3-character currency code'); + } + if ($price['price'] < 0) { + throw new Exception('Price must be non-negative'); + } + } + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $productId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Delete product + * + * @param string $productId Product ID + * @return GeneralResponse + * @throws Exception + */ + public function deleteProduct($productId = '') + { + if (empty($productId)) { + throw new Exception('Product ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $productId); + + $response = $this->httpService->getHttpClient()->delete($endpoint); + + return new GeneralResponse($response); + } + + /** + * List products + * + * @param array $filters Optional filters + * @return GeneralResponse + */ + public function listProducts(array $filters = []) + { + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->get($endpoint, $filters); + + return new GeneralResponse($response); + } + + /** + * Search products by SKU + * + * @param string $sku Product SKU + * @return GeneralResponse + * @throws Exception + */ + public function getProductBySku($sku = '') + { + if (empty($sku)) { + throw new Exception('Product SKU is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint); + $params = ['sku' => $sku]; + + $response = $this->httpService->getHttpClient()->get($endpoint, $params); + + return new GeneralResponse($response); + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Tax.php b/lib/FasterPay/Services/Business/EInvoice/Tax.php new file mode 100644 index 0000000..89c32a0 --- /dev/null +++ b/lib/FasterPay/Services/Business/EInvoice/Tax.php @@ -0,0 +1,156 @@ + 100)) { + throw new Exception('Percentage tax value must be between 0 and 100'); + } + + if ($params['type'] === 'flat' && $params['value'] < 0) { + throw new Exception('Flat tax value must be non-negative'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->post($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Get tax details + * + * @param string $taxId Tax ID + * @return GeneralResponse + * @throws Exception + */ + public function getTax($taxId = '') + { + if (empty($taxId)) { + throw new Exception('Tax ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $taxId); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Update tax + * + * @param string $taxId Tax ID + * @param array $params Updated tax parameters + * @return GeneralResponse + * @throws Exception + */ + public function updateTax($taxId = '', array $params = []) + { + if (empty($taxId)) { + throw new Exception('Tax ID is required'); + } + + // Validate tax type if provided + if (!empty($params['type'])) { + $validTypes = ['flat', 'percentage']; + if (!in_array($params['type'], $validTypes)) { + throw new Exception('Tax type must be either "flat" or "percentage"'); + } + } + + // Validate value if provided + if (isset($params['value'])) { + if (!is_numeric($params['value'])) { + throw new Exception('Tax value must be numeric'); + } + + if (!empty($params['type'])) { + if ($params['type'] === 'percentage' && ($params['value'] < 0 || $params['value'] > 100)) { + throw new Exception('Percentage tax value must be between 0 and 100'); + } + + if ($params['type'] === 'flat' && $params['value'] < 0) { + throw new Exception('Flat tax value must be non-negative'); + } + } + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $taxId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Delete tax + * + * @param string $taxId Tax ID + * @return GeneralResponse + * @throws Exception + */ + public function deleteTax($taxId = '') + { + if (empty($taxId)) { + throw new Exception('Tax ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $taxId); + + $response = $this->httpService->getHttpClient()->delete($endpoint); + + return new GeneralResponse($response); + } + + /** + * List taxes + * + * @param array $filters Optional filters + * @return GeneralResponse + */ + public function listTaxes(array $filters = []) + { + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->get($endpoint, $filters); + + return new GeneralResponse($response); + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Template.php b/lib/FasterPay/Services/Business/EInvoice/Template.php new file mode 100644 index 0000000..4de2e8b --- /dev/null +++ b/lib/FasterPay/Services/Business/EInvoice/Template.php @@ -0,0 +1,148 @@ +isValidHexColor($params['colors']['primary'])) { + throw new Exception('Primary color must be a valid hex color'); + } + if (!empty($params['colors']['secondary']) && !$this->isValidHexColor($params['colors']['secondary'])) { + throw new Exception('Secondary color must be a valid hex color'); + } + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->post($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Get template details + * + * @param string $templateId Template ID + * @return GeneralResponse + * @throws Exception + */ + public function getTemplate($templateId = '') + { + if (empty($templateId)) { + throw new Exception('Template ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $templateId); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Update template + * + * @param string $templateId Template ID + * @param array $params Updated template parameters + * @return GeneralResponse + * @throws Exception + */ + public function updateTemplate($templateId = '', array $params = []) + { + if (empty($templateId)) { + throw new Exception('Template ID is required'); + } + + // Validate colors if provided + if (!empty($params['colors'])) { + if (!empty($params['colors']['primary']) && !$this->isValidHexColor($params['colors']['primary'])) { + throw new Exception('Primary color must be a valid hex color'); + } + if (!empty($params['colors']['secondary']) && !$this->isValidHexColor($params['colors']['secondary'])) { + throw new Exception('Secondary color must be a valid hex color'); + } + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $templateId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Delete template + * + * @param string $templateId Template ID + * @return GeneralResponse + * @throws Exception + */ + public function deleteTemplate($templateId = '') + { + if (empty($templateId)) { + throw new Exception('Template ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $templateId); + + $response = $this->httpService->getHttpClient()->delete($endpoint); + + return new GeneralResponse($response); + } + + /** + * List templates + * + * @param array $filters Optional filters + * @return GeneralResponse + */ + public function listTemplates(array $filters = []) + { + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->get($endpoint, $filters); + + return new GeneralResponse($response); + } + + /** + * Validate hex color format + * + * @param string $color Hex color string + * @return bool + */ + private function isValidHexColor($color) + { + return preg_match('/^#[a-f0-9]{6}$/i', $color); + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/Payout.php b/lib/FasterPay/Services/Business/Payout.php new file mode 100644 index 0000000..3d9c35b --- /dev/null +++ b/lib/FasterPay/Services/Business/Payout.php @@ -0,0 +1,159 @@ +httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->post($endpoint, $params); + + return new GeneralResponse($response); + } + + /** + * Get payout details + * + * @param string $payoutId Payout ID + * @return GeneralResponse + * @throws Exception + */ + public function getPayoutDetails($payoutId = '') + { + if (empty($payoutId)) { + throw new Exception('Payout ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $payoutId); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Get payout list + * + * @param array $filters Optional filters (limit, offset, status, etc.) + * @return GeneralResponse + */ + public function getPayoutList(array $filters = []) + { + $endpoint = $this->httpService->getEndPoint($this->endpoint); + + $response = $this->httpService->getHttpClient()->get($endpoint, $filters); + + return new GeneralResponse($response); + } + + /** + * Cancel a payout + * + * @param string $payoutId Payout ID + * @return GeneralResponse + * @throws Exception + */ + public function cancelPayout($payoutId = '') + { + if (empty($payoutId)) { + throw new Exception('Payout ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $payoutId . '/cancel'); + + $response = $this->httpService->getHttpClient()->post($endpoint); + + return new GeneralResponse($response); + } + + /** + * Get payout status + * + * @param string $payoutId Payout ID + * @return GeneralResponse + * @throws Exception + */ + public function getPayoutStatus($payoutId = '') + { + if (empty($payoutId)) { + throw new Exception('Payout ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $payoutId . '/status'); + + $response = $this->httpService->getHttpClient()->get($endpoint); + + return new GeneralResponse($response); + } + + /** + * Retry a failed payout + * + * @param string $payoutId Payout ID + * @return GeneralResponse + * @throws Exception + */ + public function retryPayout($payoutId = '') + { + if (empty($payoutId)) { + throw new Exception('Payout ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $payoutId . '/retry'); + + $response = $this->httpService->getHttpClient()->post($endpoint); + + return new GeneralResponse($response); + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/HttpService.php b/lib/FasterPay/Services/HttpService.php index 17dcece..7247a3a 100644 --- a/lib/FasterPay/Services/HttpService.php +++ b/lib/FasterPay/Services/HttpService.php @@ -2,15 +2,20 @@ namespace FasterPay\Services; +use FasterPay\BusinessGateway; use FasterPay\Gateway; class HttpService implements HttpServiceInterface { + /** + * @var Gateway|BusinessGateway + */ protected $client; - protected $endpoint; - - public function __construct(Gateway $client) + /** + * @param Gateway|BusinessGateway $client + */ + public function __construct($client) { $this->client = $client; } @@ -28,7 +33,7 @@ public function getEndPoint($endpoint = '') public function __call($function, $params) { if (method_exists($this, $function)) { - return call_user_func_array(array($this, $function), $params); + return call_user_func_array([$this, $function], $params); } } } diff --git a/lib/FasterPay/Services/Payment.php b/lib/FasterPay/Services/Payment.php index 0f0ef4a..0f2965b 100644 --- a/lib/FasterPay/Services/Payment.php +++ b/lib/FasterPay/Services/Payment.php @@ -19,7 +19,7 @@ public function refund($orderId = 0, $amount = 0) } $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $orderId . '/refund'); - $params = array('amount' => $amount); + $params = ['amount' => $amount]; $response = $this->httpService->getHttpClient()->post($endpoint, $params); diff --git a/lib/FasterPay/Services/Pingback.php b/lib/FasterPay/Services/Pingback.php index 34299f5..266d5da 100644 --- a/lib/FasterPay/Services/Pingback.php +++ b/lib/FasterPay/Services/Pingback.php @@ -1,7 +1,7 @@ gateway = $gateway; } diff --git a/lib/FasterPay/Services/Signature.php b/lib/FasterPay/Services/Signature.php index 92eb11d..92732b8 100644 --- a/lib/FasterPay/Services/Signature.php +++ b/lib/FasterPay/Services/Signature.php @@ -1,7 +1,7 @@ gateway = $gateway; } From 445b1e83b5c6daa1abee12edc725c0380e881aba Mon Sep 17 00:00:00 2001 From: James Date: Tue, 5 Aug 2025 14:35:21 +0700 Subject: [PATCH 02/20] update --- code-samples/business/contact.php | 278 ++-- code-samples/business/e-invoice/invoice.php | 1274 ++++++++++++++--- lib/FasterPay/HttpClient.php | 67 +- lib/FasterPay/Services/Business/Contact.php | 257 +--- .../Services/Business/EInvoice/Invoice.php | 314 +--- 5 files changed, 1244 insertions(+), 946 deletions(-) diff --git a/code-samples/business/contact.php b/code-samples/business/contact.php index 8837056..7f6cec8 100644 --- a/code-samples/business/contact.php +++ b/code-samples/business/contact.php @@ -11,25 +11,18 @@ echo "FasterPay Contact API Examples\n"; echo "===============================\n\n"; -// Example 1: Create a new contact -echo "1. Creating a new contact\n"; -echo "-------------------------\n"; +// Example 1: Create a new individual contact +echo "1. Creating a new individual contact\n"; +echo "------------------------------------\n"; $contactData = [ - 'type' => 'individual', - 'first_name' => 'Jane', + 'email' => 'john.smith@example.com', + 'phone' => '2015550124', + 'phone_country_code' => 'US', + 'first_name' => 'John', 'last_name' => 'Smith', - 'email' => 'jane.smith@example.com', - 'phone' => '+1-555-234-5678', - 'company' => 'Tech Solutions Inc', - 'job_title' => 'Product Manager', - 'status' => 'active', - 'tags' => ['customer', 'premium'], - 'notes' => 'High-value customer, prefers email communication', - 'custom_fields' => [ - 'customer_since' => '2023-01-15', - 'preferred_contact_method' => 'email' - ] + 'country' => 'US', + 'favorite' => true ]; try { @@ -38,11 +31,12 @@ if ($contactResponse->isSuccessful()) { echo "✓ Contact created successfully\n"; $responseData = $contactResponse->getDecodeResponse(); - $contactId = $responseData['contact_id'] ?? 'contact_' . time(); - echo " Contact ID: $contactId\n"; - echo " Name: {$contactData['first_name']} {$contactData['last_name']}\n"; - echo " Email: {$contactData['email']}\n"; - echo " Phone: {$contactData['phone']}\n"; + $contactId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'CT-' . time(); + echo " Contact ID: " . $contactId . "\n"; + echo " Name: " . $contactData['first_name'] . " " . $contactData['last_name'] . "\n"; + echo " Email: " . $contactData['email'] . "\n"; + echo " Phone: " . $contactData['phone'] . "\n"; + echo " Country: " . $contactData['country'] . "\n"; } else { echo "✗ Error: " . $contactResponse->getErrors()->getMessage() . "\n"; } @@ -52,63 +46,33 @@ echo "\n"; -// Example 2: Create a business contact -echo "2. Creating a business contact\n"; -echo "------------------------------\n"; - -$businessContactData = [ - 'type' => 'business', - 'name' => 'Global Enterprise Solutions', - 'email' => 'contact@globalenterprise.com', - 'phone' => '+1-555-987-6543', - 'website' => 'https://globalenterprise.com', - 'industry' => 'Technology', - 'employee_count' => '500-1000', - 'annual_revenue' => '50000000', - 'status' => 'active', - 'primary_contact' => [ - 'first_name' => 'Robert', - 'last_name' => 'Johnson', - 'email' => 'robert.johnson@globalenterprise.com', - 'job_title' => 'CFO' - ] -]; - -try { - $businessContactResponse = $businessGateway->contactService()->createContact($businessContactData); - - if ($businessContactResponse->isSuccessful()) { - echo "✓ Business contact created successfully\n"; - $responseData = $businessContactResponse->getDecodeResponse(); - $businessContactId = $responseData['contact_id'] ?? 'business_contact_' . time(); - echo " Contact ID: $businessContactId\n"; - echo " Company: {$businessContactData['name']}\n"; - echo " Industry: {$businessContactData['industry']}\n"; - echo " Primary Contact: {$businessContactData['primary_contact']['first_name']} {$businessContactData['primary_contact']['last_name']}\n"; - } else { - echo "✗ Error: " . $businessContactResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 3: Get contact by email -echo "3. Finding contact by email\n"; +// Example 2: Create another contact +echo "2. Creating another contact\n"; echo "---------------------------\n"; +$secondContactData = [ + 'email' => 'jane.doe@example.com', + 'phone' => '2015550987', + 'phone_country_code' => 'US', + 'first_name' => 'Jane', + 'last_name' => 'Doe', + 'country' => 'US', + 'favorite' => false +]; + try { - $emailResponse = $businessGateway->contactService()->getContactByEmail('jane.smith@example.com'); - - if ($emailResponse->isSuccessful()) { - echo "✓ Contact found by email\n"; - $contactData = $emailResponse->getDecodeResponse(); - echo " Email: jane.smith@example.com\n"; - echo " Name: " . ($contactData['first_name'] ?? 'Jane') . " " . ($contactData['last_name'] ?? 'Smith') . "\n"; - echo " Status: " . ($contactData['status'] ?? 'active') . "\n"; + $secondContactResponse = $businessGateway->contactService()->createContact($secondContactData); + + if ($secondContactResponse->isSuccessful()) { + echo "✓ Second contact created successfully\n"; + $responseData = $secondContactResponse->getDecodeResponse(); + $secondContactId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'CT-2-' . time(); + echo " Contact ID: " . $secondContactId . "\n"; + echo " Name: " . $secondContactData['first_name'] . " " . $secondContactData['last_name'] . "\n"; + echo " Email: " . $secondContactData['email'] . "\n"; + echo " Phone: " . $secondContactData['phone'] . "\n"; } else { - echo "✗ Error: " . $emailResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $secondContactResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -116,31 +80,27 @@ echo "\n"; -// Example 4: Add address to contact -echo "4. Adding address to contact\n"; -echo "----------------------------\n"; - -$contactId = 'contact_' . time(); // In real scenario, use actual contact ID -$addressData = [ - 'type' => 'home', - 'street' => '456 Oak Avenue', - 'city' => 'San Francisco', - 'state' => 'CA', - 'postal_code' => '94102', - 'country_code' => 'US', - 'is_primary' => true -]; +// Example 3: Get contact details +echo "3. Getting contact details\n"; +echo "--------------------------\n"; try { - $addressResponse = $businessGateway->contactService()->addContactAddress($contactId, $addressData); - - if ($addressResponse->isSuccessful()) { - echo "✓ Address added to contact successfully\n"; - echo " Contact ID: $contactId\n"; - echo " Address: {$addressData['street']}, {$addressData['city']}, {$addressData['state']}\n"; - echo " Type: {$addressData['type']}\n"; + $detailsResponse = $businessGateway->contactService()->getContact($contactId); + + if ($detailsResponse->isSuccessful()) { + echo "✓ Contact details retrieved successfully\n"; + $details = $detailsResponse->getDecodeResponse(); + + if (isset($details['data'])) { + $contact = $details['data']; + echo " ID: " . (isset($contact['id']) ? $contact['id'] : 'N/A') . "\n"; + echo " Name: " . (isset($contact['first_name']) ? $contact['first_name'] : '') . " " . (isset($contact['last_name']) ? $contact['last_name'] : '') . "\n"; + echo " Email: " . (isset($contact['email']) ? $contact['email'] : 'N/A') . "\n"; + echo " Phone: " . (isset($contact['phone_full_number']) ? $contact['phone_full_number'] : 'N/A') . "\n"; + echo " Country: " . (isset($contact['country']) ? $contact['country'] : 'N/A') . "\n"; + } } else { - echo "✗ Error: " . $addressResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -148,28 +108,27 @@ echo "\n"; -// Example 5: Search contacts -echo "5. Searching contacts\n"; -echo "---------------------\n"; +// Example 4: Update contact +echo "4. Updating contact information\n"; +echo "-------------------------------\n"; -$searchParams = [ - 'query' => 'smith', - 'type' => 'individual', - 'status' => 'active', - 'tags' => ['customer'], - 'limit' => 10 +$updateData = [ + 'phone' => '2015559999', + 'favorite' => false, + 'first_name' => 'Jonathan' ]; try { - $searchResponse = $businessGateway->contactService()->searchContacts($searchParams); + $updateResponse = $businessGateway->contactService()->updateContact($contactId, $updateData); - if ($searchResponse->isSuccessful()) { - echo "✓ Contact search completed\n"; - echo " Query: 'smith'\n"; - echo " Filter: Active individual customers\n"; - echo " (In a real scenario, this would return matching contacts)\n"; + if ($updateResponse->isSuccessful()) { + echo "✓ Contact updated successfully\n"; + echo " Contact ID: " . $contactId . "\n"; + echo " New phone: " . $updateData['phone'] . "\n"; + echo " Updated name: " . $updateData['first_name'] . "\n"; + echo " Favorite: " . ($updateData['favorite'] ? 'Yes' : 'No') . "\n"; } else { - echo "✗ Error: " . $searchResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -177,30 +136,33 @@ echo "\n"; -// Example 6: Update contact -echo "6. Updating contact information\n"; -echo "-------------------------------\n"; - -$updateData = [ - 'job_title' => 'Senior Product Manager', - 'phone' => '+1-555-234-9999', - 'notes' => 'Promoted to Senior PM. Updated contact preferences.', - 'custom_fields' => [ - 'last_interaction' => date('Y-m-d'), - 'account_value' => '15000' - ] +// Example 5: Create another contact for listing +echo "5. Creating a third contact for demonstration\n"; +echo "---------------------------------------------\n"; + +$thirdContactData = [ + 'email' => 'mike.wilson@example.com', + 'phone' => '2015550555', + 'phone_country_code' => 'US', + 'first_name' => 'Mike', + 'last_name' => 'Wilson', + 'country' => 'US', + 'favorite' => true ]; try { - $updateResponse = $businessGateway->contactService()->updateContact($contactId, $updateData); - - if ($updateResponse->isSuccessful()) { - echo "✓ Contact updated successfully\n"; - echo " Contact ID: $contactId\n"; - echo " New job title: {$updateData['job_title']}\n"; - echo " Updated phone: {$updateData['phone']}\n"; + $thirdContactResponse = $businessGateway->contactService()->createContact($thirdContactData); + + if ($thirdContactResponse->isSuccessful()) { + echo "✓ Third contact created successfully\n"; + $responseData = $thirdContactResponse->getDecodeResponse(); + $thirdContactId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'CT-3-' . time(); + echo " Contact ID: " . $thirdContactId . "\n"; + echo " Name: " . $thirdContactData['first_name'] . " " . $thirdContactData['last_name'] . "\n"; + echo " Email: " . $thirdContactData['email'] . "\n"; + echo " Favorite: " . ($thirdContactData['favorite'] ? 'Yes' : 'No') . "\n"; } else { - echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $thirdContactResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -208,19 +170,13 @@ echo "\n"; -// Example 7: List contacts with filters -echo "7. Listing contacts with filters\n"; +// Example 6: List contacts with filters +echo "6. Listing contacts with filters\n"; echo "--------------------------------\n"; $filters = [ - 'type' => 'individual', - 'status' => 'active', - 'has_email' => true, - 'created_after' => '2023-01-01', 'limit' => 25, - 'offset' => 0, - 'sort' => 'last_name', - 'order' => 'asc' + 'offset' => 0 ]; try { @@ -228,11 +184,24 @@ if ($listResponse->isSuccessful()) { echo "✓ Contact list retrieved successfully\n"; - echo " Filter: Active individuals with email addresses\n"; - echo " Created after: 2023-01-01\n"; - echo " Sorted by: Last name (ascending)\n"; echo " Limit: 25 contacts\n"; - echo " (In a real scenario, this would show actual contact data)\n"; + + $listData = $listResponse->getDecodeResponse(); + if (isset($listData['data']) && is_array($listData['data'])) { + echo " Found " . count($listData['data']) . " contacts\n"; + + // Display first few contacts + $contacts = array_slice($listData['data'], 0, 3); + foreach ($contacts as $contact) { + $name = (isset($contact['first_name']) ? $contact['first_name'] : '') . ' ' . (isset($contact['last_name']) ? $contact['last_name'] : ''); + $email = isset($contact['email']) ? $contact['email'] : 'No email'; + echo " - " . trim($name) . " (" . $email . ")\n"; + } + + if (count($listData['data']) > 3) { + echo " ... and " . (count($listData['data']) - 3) . " more\n"; + } + } } else { echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; } @@ -242,19 +211,20 @@ echo "\n"; -// Example 8: Get contact addresses -echo "8. Getting contact addresses\n"; -echo "----------------------------\n"; +// Example 7: Delete a contact +echo "7. Deleting a contact\n"; +echo "---------------------\n"; + +$contactToDelete = isset($thirdContactId) ? $thirdContactId : 'CT-DELETE-' . time(); try { - $addressesResponse = $businessGateway->contactService()->getContactAddresses($contactId); + $deleteResponse = $businessGateway->contactService()->deleteContact($contactToDelete); - if ($addressesResponse->isSuccessful()) { - echo "✓ Contact addresses retrieved successfully\n"; - echo " Contact ID: $contactId\n"; - echo " (In a real scenario, this would show all addresses for the contact)\n"; + if ($deleteResponse->isSuccessful()) { + echo "✓ Contact deleted successfully\n"; + echo " Deleted Contact ID: " . $contactToDelete . "\n"; } else { - echo "✗ Error: " . $addressesResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; diff --git a/code-samples/business/e-invoice/invoice.php b/code-samples/business/e-invoice/invoice.php index 126810d..81dfdc5 100644 --- a/code-samples/business/e-invoice/invoice.php +++ b/code-samples/business/e-invoice/invoice.php @@ -11,81 +11,87 @@ echo "FasterPay E-Invoice API Examples\n"; echo "=================================\n\n"; -// Example 1: Create a new e-invoice -echo "1. Creating a new e-invoice\n"; -echo "---------------------------\n"; +// Example 1: Create a new e-invoice with embedded components +echo "1. Creating a new e-invoice with embedded components\n"; +echo "----------------------------------------------------\n"; $invoiceData = [ - 'invoice_number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'issue_date' => date('Y-m-d'), - 'due_date' => date('Y-m-d', strtotime('+30 days')), 'currency' => 'USD', - 'status' => 'draft', - 'customer' => [ - 'id' => 'customer_123', - 'name' => 'Acme Corporation', - 'email' => 'billing@acme.com', - 'phone' => '+1-555-123-4567', - 'tax_id' => '12-3456789', - 'billing_address' => [ - 'street' => '123 Business Blvd', - 'city' => 'New York', - 'state' => 'NY', - 'postal_code' => '10001', - 'country_code' => 'US' - ] - ], - 'items' => [ - [ - 'description' => 'Website Development Services', - 'quantity' => 1, - 'unit_price' => 5000.00, - 'tax_rate' => 8.25, - 'category' => 'services' + 'summary' => 'Website development project invoice', + 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => 'CT-250527-AZARCIJE', + 'template' => [ + 'name' => 'Project Template', + 'footer' => 'Thank you for your business!', + 'colors' => [ + 'primary' => '#2563eb', + 'secondary' => '#f8fafc' ], - [ - 'description' => 'Monthly Hosting Package', - 'quantity' => 12, - 'unit_price' => 99.99, - 'tax_rate' => 8.25, - 'category' => 'services' + 'localized_address' => [ + 'address_line1' => '123 Business Ave', + 'locality' => 'San Francisco', + 'administrative_area' => 'CA', + 'postal_code' => '94105' ], + 'country_code' => 'US' + ], + 'tax' => [ + 'name' => 'Sales Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% sales tax' + ], + 'discount' => [ + 'name' => 'Early Payment', + 'type' => 'flat', + 'value' => 50.0, + 'currency' => 'USD', + 'description' => '$50 early payment discount' + ], + 'items' => [ [ - 'description' => 'SSL Certificate', + 'price' => 2500.00, 'quantity' => 1, - 'unit_price' => 150.00, - 'tax_rate' => 8.25, - 'category' => 'products' + 'product' => [ + 'sku' => 'WEB-DEV-PROJ', + 'type' => 'digital', + 'name' => 'Website Development', + 'description' => 'Complete website development project', + 'prices' => [ + [ + 'price' => 2500.00, + 'currency' => 'USD' + ] + ] + ], + 'tax' => [ + 'name' => 'Item Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% tax on this item' + ], + 'discount' => [ + 'name' => 'Item Discount', + 'type' => 'percentage', + 'value' => 5, + 'description' => '5% discount on this item' + ] ] - ], - 'payment_terms' => 'Net 30', - 'notes' => 'Thank you for your business. Payment is due within 30 days.', - 'template' => 'standard', - 'send_automatically' => false + ] ]; try { $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceData); if ($invoiceResponse->isSuccessful()) { - echo "✓ E-invoice created successfully\n"; + echo "✓ E-invoice with embedded components created successfully\n"; $responseData = $invoiceResponse->getDecodeResponse(); - $invoiceId = $responseData['invoice_id'] ?? 'inv_' . time(); - echo " Invoice ID: $invoiceId\n"; - echo " Invoice Number: {$invoiceData['invoice_number']}\n"; - echo " Customer: {$invoiceData['customer']['name']}\n"; - - // Calculate totals - $subtotal = 0; - foreach ($invoiceData['items'] as $item) { - $subtotal += $item['quantity'] * $item['unit_price']; - } - $tax = $subtotal * 0.0825; // 8.25% tax - $total = $subtotal + $tax; - - echo " Subtotal: $" . number_format($subtotal, 2) . "\n"; - echo " Tax: $" . number_format($tax, 2) . "\n"; - echo " Total: $" . number_format($total, 2) . "\n"; + $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Invoice Number: " . $invoiceData['number'] . "\n"; + echo " Currency: " . $invoiceData['currency'] . "\n"; + echo " Items: " . count($invoiceData['items']) . "\n"; + echo " Template: " . $invoiceData['template']['name'] . "\n"; } else { echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; } @@ -95,30 +101,39 @@ echo "\n"; -// Example 5: Mark invoice as paid -echo "5. Marking invoice as paid\n"; -echo "--------------------------\n"; +// Example 2: Create template with logo file (if you have a logo file) +echo "2. Creating invoice template with logo\n"; +echo "--------------------------------------\n"; -$paymentData = [ - 'amount' => 6558.87, // Total amount from invoice - 'payment_date' => date('Y-m-d'), - 'payment_method' => 'bank_transfer', - 'reference' => 'TXN-' . time(), - 'notes' => 'Payment received via bank transfer' +$templateData = [ + 'name' => 'Professional Template with Logo', + 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', + 'colors' => [ + 'primary' => '#2563eb', + 'secondary' => '#f8fafc' + ], + 'localized_address' => [ + 'address_line1' => '123 Business Avenue', + 'locality' => 'San Francisco', + 'administrative_area' => 'CA', + 'postal_code' => '94105' + ], + 'country_code' => 'US' + // Note: For file upload, you would add: 'logo' => '@/path/to/logo.png' ]; try { - $paidResponse = $businessGateway->eInvoiceService()->markAsPaid($invoiceId, $paymentData); + $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); - if ($paidResponse->isSuccessful()) { - echo "✓ Invoice marked as paid successfully\n"; - echo " Invoice ID: $invoiceId\n"; - echo " Amount: $" . number_format($paymentData['amount'], 2) . "\n"; - echo " Payment Date: {$paymentData['payment_date']}\n"; - echo " Method: {$paymentData['payment_method']}\n"; - echo " Reference: {$paymentData['reference']}\n"; + if ($templateResponse->isSuccessful()) { + echo "✓ Invoice template created successfully\n"; + $responseData = $templateResponse->getDecodeResponse(); + $templateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-' . time(); + echo " Template ID: " . $templateId . "\n"; + echo " Name: " . $templateData['name'] . "\n"; + echo " Primary Color: " . $templateData['colors']['primary'] . "\n"; } else { - echo "✗ Error: " . $paidResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $templateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -126,32 +141,30 @@ echo "\n"; -// Example 6: Search invoices -echo "6. Searching invoices\n"; -echo "---------------------\n"; - -$searchParams = [ - 'customer_name' => 'Acme', - 'status' => 'paid', - 'amount_min' => 1000, - 'amount_max' => 10000, - 'date_from' => '2024-01-01', - 'date_to' => '2024-12-31', - 'limit' => 20 +// Example 3: Create tax +echo "3. Creating tax configuration\n"; +echo "-----------------------------\n"; + +$taxData = [ + 'name' => 'Sales Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% sales tax rate' ]; try { - $searchResponse = $businessGateway->eInvoiceService()->searchInvoices($searchParams); - - if ($searchResponse->isSuccessful()) { - echo "✓ Invoice search completed\n"; - echo " Customer: Contains 'Acme'\n"; - echo " Status: Paid\n"; - echo " Amount range: $1,000 - $10,000\n"; - echo " Date range: 2024\n"; - echo " (In a real scenario, this would return matching invoices)\n"; + $taxResponse = $businessGateway->eInvoiceTaxService()->createTax($taxData); + + if ($taxResponse->isSuccessful()) { + echo "✓ Tax created successfully\n"; + $responseData = $taxResponse->getDecodeResponse(); + $taxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-' . time(); + echo " Tax ID: " . $taxId . "\n"; + echo " Name: " . $taxData['name'] . "\n"; + echo " Type: " . $taxData['type'] . "\n"; + echo " Rate: " . ($taxData['value'] * 100) . "%\n"; } else { - echo "✗ Error: " . $searchResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -159,31 +172,30 @@ echo "\n"; -// Example 7: List invoices with filters -echo "7. Listing invoices with filters\n"; -echo "--------------------------------\n"; +// Example 4: Create discount +echo "4. Creating discount offer\n"; +echo "--------------------------\n"; -$filters = [ - 'status' => 'sent', - 'overdue' => true, +$discountData = [ + 'name' => 'Early Bird Discount', + 'type' => 'flat', + 'value' => 50.0, 'currency' => 'USD', - 'limit' => 50, - 'offset' => 0, - 'sort' => 'due_date', - 'order' => 'asc' + 'description' => '$50 discount for early payment' ]; try { - $listResponse = $businessGateway->eInvoiceService()->listInvoices($filters); + $discountResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($discountData); - if ($listResponse->isSuccessful()) { - echo "✓ Invoice list retrieved successfully\n"; - echo " Filter: Overdue sent invoices in USD\n"; - echo " Sorted by: Due date (ascending)\n"; - echo " Limit: 50 invoices\n"; - echo " (In a real scenario, this would show actual invoice data)\n"; + if ($discountResponse->isSuccessful()) { + echo "✓ Discount created successfully\n"; + $responseData = $discountResponse->getDecodeResponse(); + $discountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-' . time(); + echo " Discount ID: " . $discountId . "\n"; + echo " Name: " . $discountData['name'] . "\n"; + echo " Value: $" . $discountData['value'] . " " . $discountData['currency'] . "\n"; } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -191,22 +203,37 @@ echo "\n"; -// Example 8: Get invoice status -echo "8. Getting invoice status\n"; -echo "-------------------------\n"; +// Example 5: Create product with image (if you have an image file) +echo "5. Creating product with image\n"; +echo "------------------------------\n"; + +$productData = [ + 'sku' => 'WEB-DEV-001', + 'type' => 'digital', + 'name' => 'Website Development Package', + 'description' => 'Complete website development with modern responsive design', + 'prices' => [ + [ + 'price' => 2500.00, + 'currency' => 'USD' + ] + ] + // Note: For file upload, you would add: 'image' => '@/path/to/product-image.jpg' +]; try { - $statusResponse = $businessGateway->eInvoiceService()->getInvoiceStatus($invoiceId); + $productResponse = $businessGateway->eInvoiceProductService()->createProduct($productData); - if ($statusResponse->isSuccessful()) { - echo "✓ Invoice status retrieved successfully\n"; - $statusData = $statusResponse->getDecodeResponse(); - echo " Invoice ID: $invoiceId\n"; - echo " Status: " . ($statusData['status'] ?? 'paid') . "\n"; - echo " Last updated: " . ($statusData['updated_at'] ?? date('Y-m-d H:i:s')) . "\n"; - echo " Payment status: " . ($statusData['payment_status'] ?? 'completed') . "\n"; + if ($productResponse->isSuccessful()) { + echo "✓ Product created successfully\n"; + $responseData = $productResponse->getDecodeResponse(); + $productId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-' . time(); + echo " Product ID: " . $productId . "\n"; + echo " SKU: " . $productData['sku'] . "\n"; + echo " Name: " . $productData['name'] . "\n"; + echo " Type: " . $productData['type'] . "\n"; } else { - echo "✗ Error: " . $statusResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $productResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -214,28 +241,27 @@ echo "\n"; -// Example 9: Update invoice item -echo "9. Updating invoice item\n"; -echo "------------------------\n"; +// Example 6: Update invoice using POST with _method=PUT +echo "6. Updating invoice\n"; +echo "-------------------\n"; -$itemId = 'item_' . time(); // In real scenario, use actual item ID -$itemUpdateData = [ - 'description' => 'Premium Domain Registration (Updated)', - 'unit_price' => 39.99, - 'notes' => 'Upgraded to premium domain package' +$invoiceId = isset($invoiceId) ? $invoiceId : 'FPBIV-' . time(); +$updateData = [ + 'summary' => 'Updated website development project invoice', + 'template' => [ + 'footer' => 'Updated footer - Thank you for choosing our services!' + ] ]; try { - $itemUpdateResponse = $businessGateway->eInvoiceService()->updateInvoiceItem($invoiceId, $itemId, $itemUpdateData); - - if ($itemUpdateResponse->isSuccessful()) { - echo "✓ Invoice item updated successfully\n"; - echo " Invoice ID: $invoiceId\n"; - echo " Item ID: $itemId\n"; - echo " New description: {$itemUpdateData['description']}\n"; - echo " New price: $" . number_format($itemUpdateData['unit_price'], 2) . "\n"; + $updateResponse = $businessGateway->eInvoiceService()->updateInvoice($invoiceId, $updateData); + + if ($updateResponse->isSuccessful()) { + echo "✓ Invoice updated successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Updated summary and template footer\n"; } else { - echo "✗ Error: " . $itemUpdateResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -243,58 +269,135 @@ echo "\n"; -// Example 10: Create recurring invoice template -echo "10. Creating recurring invoice\n"; +// Example 7: Update invoice status +echo "7. Updating invoice status\n"; +echo "--------------------------\n"; + +$statusParams = [ + 'status' => 'sent', + 'notes' => 'Invoice sent to customer via email' +]; + +try { + $statusResponse = $businessGateway->eInvoiceService()->updateInvoiceStatus($invoiceId, $statusParams); + + if ($statusResponse->isSuccessful()) { + echo "✓ Invoice status updated successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " New status: " . $statusParams['status'] . "\n"; + echo " Notes: " . $statusParams['notes'] . "\n"; + } else { + echo "✗ Error: " . $statusResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: Preview invoice (HTML) +echo "8. Previewing invoice HTML\n"; +echo "--------------------------\n"; + +try { + $previewResponse = $businessGateway->eInvoiceService()->previewInvoice($invoiceId); + + if ($previewResponse->isSuccessful()) { + echo "✓ Invoice preview generated successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Preview format: HTML\n"; + echo " (HTML content received - can be displayed in browser)\n"; + } else { + echo "✗ Error: " . $previewResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 9: Send invoice to customer +echo "9. Sending invoice to customer\n"; echo "------------------------------\n"; -$recurringInvoiceData = [ - 'template_name' => 'Monthly Hosting Service', - 'invoice_number_pattern' => 'HOST-{YYYY}-{MM}-{####}', - 'recurrence' => 'monthly', - 'start_date' => date('Y-m-d'), - 'end_date' => date('Y-m-d', strtotime('+1 year')), - 'customer' => [ - 'id' => 'customer_456', - 'name' => 'Tech Startup LLC', - 'email' => 'accounts@techstartup.com' - ], - 'items' => [ - [ - 'description' => 'Premium Hosting Package', - 'quantity' => 1, - 'unit_price' => 299.99, - 'tax_rate' => 8.25 - ], - [ - 'description' => 'SSL Certificate Renewal', - 'quantity' => 1, - 'unit_price' => 99.99, - 'tax_rate' => 8.25 - ] - ], - 'auto_send' => true, - 'payment_terms' => 'Net 15' +$sendParams = [ + 'test' => false // According to API docs, main parameter is 'test' ]; try { - $recurringResponse = $businessGateway->eInvoiceService()->createInvoice($recurringInvoiceData); - - if ($recurringResponse->isSuccessful()) { - echo "✓ Recurring invoice template created successfully\n"; - $responseData = $recurringResponse->getDecodeResponse(); - $templateId = $responseData['template_id'] ?? 'template_' . time(); - echo " Template ID: $templateId\n"; - echo " Template Name: {$recurringInvoiceData['template_name']}\n"; - echo " Recurrence: {$recurringInvoiceData['recurrence']}\n"; - echo " Customer: {$recurringInvoiceData['customer']['name']}\n"; - echo " Monthly Amount: $" . number_format(399.98 * 1.0825, 2) . " (including tax)\n"; + $sendResponse = $businessGateway->eInvoiceService()->sendInvoice($invoiceId, $sendParams); + + if ($sendResponse->isSuccessful()) { + echo "✓ Invoice sent successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Sent to customer's email address\n"; } else { - echo "✗ Error: " . $recurringResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $sendResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; } +echo "\n"; + +// Example 10: Download invoice PDF (file response) +echo "10. Downloading invoice PDF\n"; +echo "---------------------------\n"; + +try { + // downloadInvoicePdf returns raw file data, not GeneralResponse + $downloadResponse = $businessGateway->eInvoiceService()->downloadInvoicePdf($invoiceId); + + if ($downloadResponse['httpCode'] == 200) { + echo "✓ Invoice PDF downloaded successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Content-Length: " . strlen($downloadResponse['response']) . " bytes\n"; + echo " Content-Type: PDF\n"; + + // In a real application, you would save this to a file: + // $filename = 'invoice_' . $invoiceId . '.pdf'; + // file_put_contents($filename, $downloadResponse['response']); + // echo " Saved as: " . $filename . "\n"; + + echo " (File content received - would be saved as PDF in real application)\n"; + } else { + echo "✗ Error downloading PDF: HTTP " . $downloadResponse['httpCode'] . "\n"; + if (!empty($downloadResponse['response'])) { + // Try to decode error response + $errorData = json_decode($downloadResponse['response'], true); + if ($errorData && isset($errorData['message'])) { + echo " Error message: " . $errorData['message'] . "\n"; + } + } + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Invoice status handling via pingbacks (documentation example) +echo "Invoice status handling via pingbacks\n"; +echo "-------------------------------------\n"; + +echo "✓ Invoice status changes are handled via pingbacks\n"; +echo " Pingback example from API documentation:\n"; +echo " {\n"; +echo " \"event\": \"invoice.status.updated\",\n"; +echo " \"invoice\": {\n"; +echo " \"status\": \"void\",\n"; +echo " \"id\": \"FPBIV-250616-3UHJ\"\n"; +echo " }\n"; +echo " }\n"; +echo " \n"; +echo " For complete list of available invoice statuses, please refer to:\n"; +echo " https://docs.fasterpay.com/api#section-einvoice-api-statuses\n"; +echo " \n"; +echo " Status changes are automatically communicated via pingbacks\n"; +echo " to your configured pingback URL. The system will send status\n"; +echo " updates when invoices transition between different states\n"; +echo " during their lifecycle.\n"; + echo "\nE-Invoice API examples completed!\n"; echo "Use cases:\n"; echo "• Automated billing and invoicing\n"; @@ -304,33 +407,191 @@ echo "• Financial reporting and analytics\n"; echo "• Multi-currency invoicing\n"; echo "• Tax compliance and reporting\n"; -echo "• Customer payment portal integration\n"; +echo "• Customer payment portal integration\n"; "// Example 1: Create a new e-invoice with embedded components +echo "1. Creating a new e-invoice with embedded components\n"; +echo "----------------------------------------------------\n"; + +$invoiceData = array( + 'currency' => 'USD', + 'summary' => 'Website development project invoice', + 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => 'CT-250527-AZARCIJE', + 'template' => array( + 'name' => 'Project Template', + 'footer' => 'Thank you for your business!', + 'colors' => array( + 'primary' => '#2563eb', + 'secondary' => '#f8fafc' + ), + 'localized_address' => array( + 'address_line1' => '123 Business Ave', + 'locality' => 'San Francisco', + 'administrative_area' => 'CA', + 'postal_code' => '94105' + ), + 'country_code' => 'US' + ), + 'tax' => array( + 'name' => 'Sales Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% sales tax' + ), + 'discount' => array( + 'name' => 'Early Payment', + 'type' => 'flat', + 'value' => 50.0, + 'currency' => 'USD', + 'description' => '$50 early payment discount' + ), + 'items' => array( + array( + 'price' => 2500.00, + 'quantity' => 1, + 'product' => array( + 'sku' => 'WEB-DEV-PROJ', + 'type' => 'digital', + 'name' => 'Website Development', + 'description' => 'Complete website development project', + 'prices' => array( + array( + 'price' => 2500.00, + 'currency' => 'USD' + ) + ) + ), + 'tax' => array( + 'name' => 'Item Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% tax on this item' + ), + 'discount' => array( + 'name' => 'Item Discount', + 'type' => 'percentage', + 'value' => 5, + 'description' => '5% discount on this item' + ) + ) + ) +); + +try { + $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceData); + + if ($invoiceResponse->isSuccessful()) { + echo "✓ E-invoice with embedded components created successfully\n"; + $responseData = $invoiceResponse->getDecodeResponse(); + $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Invoice Number: " . $invoiceData['number'] . "\n"; + echo " Currency: " . $invoiceData['currency'] . "\n"; + echo " Items: " . count($invoiceData['items']) . "\n"; + echo " Template: " . $invoiceData['template']['name'] . "\n"; + } else { + echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} echo "\n"; -// Example 2: Add item to existing invoice -echo "2. Adding item to invoice\n"; -echo "-------------------------\n"; +// Example 2: Create template with logo file (if you have a logo file) +echo "2. Creating invoice template with logo\n"; +echo "--------------------------------------\n"; -$invoiceId = 'inv_' . time(); // In real scenario, use actual invoice ID -$newItem = [ - 'description' => 'Domain Registration', - 'quantity' => 1, - 'unit_price' => 29.99, - 'tax_rate' => 8.25, - 'category' => 'services' -]; +$templateData = array( + 'name' => 'Professional Template with Logo', + 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', + 'colors' => array( + 'primary' => '#2563eb', + 'secondary' => '#f8fafc' + ), + 'localized_address' => array( + 'address_line1' => '123 Business Avenue', + 'locality' => 'San Francisco', + 'administrative_area' => 'CA', + 'postal_code' => '94105' + ), + 'country_code' => 'US' + // Note: For file upload, you would add: 'logo' => '@/path/to/logo.png' +); + +try { + $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); + + if ($templateResponse->isSuccessful()) { + echo "✓ Invoice template created successfully\n"; + $responseData = $templateResponse->getDecodeResponse(); + $templateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-' . time(); + echo " Template ID: " . $templateId . "\n"; + echo " Name: " . $templateData['name'] . "\n"; + echo " Primary Color: " . $templateData['colors']['primary'] . "\n"; + } else { + echo "✗ Error: " . $templateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Create tax +echo "3. Creating tax configuration\n"; +echo "-----------------------------\n"; + +$taxData = array( + 'name' => 'Sales Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% sales tax rate' +); + +try { + $taxResponse = $businessGateway->eInvoiceTaxService()->createTax($taxData); + + if ($taxResponse->isSuccessful()) { + echo "✓ Tax created successfully\n"; + $responseData = $taxResponse->getDecodeResponse(); + $taxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-' . time(); + echo " Tax ID: " . $taxId . "\n"; + echo " Name: " . $taxData['name'] . "\n"; + echo " Type: " . $taxData['type'] . "\n"; + echo " Rate: " . ($taxData['value'] * 100) . "%\n"; + } else { + echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Create discount +echo "4. Creating discount offer\n"; +echo "--------------------------\n"; + +$discountData = array( + 'name' => 'Early Bird Discount', + 'type' => 'flat', + 'value' => 50.0, + 'currency' => 'USD', + 'description' => '$50 discount for early payment' +); try { - $itemResponse = $businessGateway->eInvoiceService()->addInvoiceItem($invoiceId, $newItem); + $discountResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($discountData); - if ($itemResponse->isSuccessful()) { - echo "✓ Item added to invoice successfully\n"; - echo " Invoice ID: $invoiceId\n"; - echo " Item: {$newItem['description']}\n"; - echo " Price: $" . number_format($newItem['unit_price'], 2) . "\n"; + if ($discountResponse->isSuccessful()) { + echo "✓ Discount created successfully\n"; + $responseData = $discountResponse->getDecodeResponse(); + $discountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-' . time(); + echo " Discount ID: " . $discountId . "\n"; + echo " Name: " . $discountData['name'] . "\n"; + echo " Value: $" . $discountData['value'] . " " . $discountData['currency'] . "\n"; } else { - echo "✗ Error: " . $itemResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -338,27 +599,94 @@ echo "\n"; -// Example 3: Send invoice to customer -echo "3. Sending invoice to customer\n"; +// Example 5: Create product with image (if you have an image file) +echo "5. Creating product with image\n"; echo "------------------------------\n"; -$sendParams = [ +$productData = array( + 'sku' => 'WEB-DEV-001', + 'type' => 'digital', + 'name' => 'Website Development Package', + 'description' => 'Complete website development with modern responsive design', + 'prices' => array( + array( + 'price' => 2500.00, + 'currency' => 'USD' + ) + ) + // Note: For file upload, you would add: 'image' => '@/path/to/product-image.jpg' +); + +try { + $productResponse = $businessGateway->eInvoiceProductService()->createProduct($productData); + + if ($productResponse->isSuccessful()) { + echo "✓ Product created successfully\n"; + $responseData = $productResponse->getDecodeResponse(); + $productId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-' . time(); + echo " Product ID: " . $productId . "\n"; + echo " SKU: " . $productData['sku'] . "\n"; + echo " Name: " . $productData['name'] . "\n"; + echo " Type: " . $productData['type'] . "\n"; + } else { + echo "✗ Error: " . $productResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: Update invoice using POST with _method=PUT +echo "6. Updating invoice\n"; +echo "-------------------\n"; + +$invoiceId = isset($invoiceId) ? $invoiceId : 'FPBIV-' . time(); +$updateData = array( + 'summary' => 'Updated website development project invoice', + 'template' => array( + 'footer' => 'Updated footer - Thank you for choosing our services!' + ) +); + +try { + $updateResponse = $businessGateway->eInvoiceService()->updateInvoice($invoiceId, $updateData); + + if ($updateResponse->isSuccessful()) { + echo "✓ Invoice updated successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Updated summary and template footer\n"; + } else { + echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: Send invoice to customer +echo "7. Sending invoice to customer\n"; +echo "------------------------------\n"; + +$sendParams = array( 'method' => 'email', - 'email' => 'billing@acme.com', - 'subject' => 'Invoice ' . ($invoiceData['invoice_number'] ?? 'INV-2024-001234') . ' from Your Company', + 'email' => 'customer@example.com', + 'subject' => 'Invoice ' . (isset($invoiceData['number']) ? $invoiceData['number'] : 'INV-001') . ' from Your Company', 'message' => 'Dear Customer, please find attached your invoice. Payment is due within 30 days.', 'copy_sender' => true, 'attach_pdf' => true -]; +); try { $sendResponse = $businessGateway->eInvoiceService()->sendInvoice($invoiceId, $sendParams); if ($sendResponse->isSuccessful()) { echo "✓ Invoice sent successfully\n"; - echo " Invoice ID: $invoiceId\n"; - echo " Sent to: {$sendParams['email']}\n"; - echo " Method: {$sendParams['method']}\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Sent to: " . $sendParams['email'] . "\n"; + echo " Method: " . $sendParams['method'] . "\n"; + echo " PDF attached: " . ($sendParams['attach_pdf'] ? 'Yes' : 'No') . "\n"; } else { echo "✗ Error: " . $sendResponse->getErrors()->getMessage() . "\n"; } @@ -368,28 +696,514 @@ echo "\n"; -// Example 4: Download invoice PDF -echo "4. Downloading invoice PDF\n"; +// Example 8: Download invoice PDF (file response) +echo "8. Downloading invoice PDF\n"; echo "--------------------------\n"; -$downloadOptions = [ +$downloadOptions = array( 'format' => 'pdf', 'template' => 'professional', 'include_payments' => true -]; +); try { - $downloadResponse = $businessGateway->eInvoiceService()->downloadInvoice($invoiceId, $downloadOptions); - - if ($downloadResponse->isSuccessful()) { - echo "✓ Invoice PDF ready for download\n"; - echo " Invoice ID: $invoiceId\n"; - echo " Format: PDF\n"; - echo " Template: Professional\n"; - echo " (In a real scenario, this would return the PDF data or download URL)\n"; + // downloadInvoicePdf returns raw file data, not GeneralResponse + $downloadResponse = $businessGateway->eInvoiceService()->downloadInvoicePdf($invoiceId, $downloadOptions); + + if ($downloadResponse['httpCode'] == 200) { + echo "✓ Invoice PDF downloaded successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Content-Length: " . strlen($downloadResponse['response']) . " bytes\n"; + echo " Content-Type: PDF\n"; + + // In a real application, you would save this to a file: + // $filename = 'invoice_' . $invoiceId . '.pdf'; + // file_put_contents($filename, $downloadResponse['response']); + // echo " Saved as: " . $filename . "\n"; + + echo " (File content received - would be saved as PDF in real application)\n"; } else { - echo "✗ Error: " . $downloadResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error downloading PDF: HTTP " . $downloadResponse['httpCode'] . "\n"; + if (!empty($downloadResponse['response'])) { + // Try to decode error response + $errorData = json_decode($downloadResponse['response'], true); + if ($errorData && isset($errorData['message'])) { + echo " Error message: " . $errorData['message'] . "\n"; + } + } } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; -} \ No newline at end of file +} + +echo "\n"; + +// Example 9: Get invoice details +echo "9. Getting invoice details\n"; +echo "--------------------------\n"; + +try { + $detailsResponse = $businessGateway->eInvoiceService()->getInvoice($invoiceId); + + if ($detailsResponse->isSuccessful()) { + echo "✓ Invoice details retrieved successfully\n"; + $details = $detailsResponse->getDecodeResponse(); + + if (isset($details['data'])) { + $invoice = $details['data']; + echo " Invoice ID: " . (isset($invoice['id']) ? $invoice['id'] : $invoiceId) . "\n"; + echo " Status: " . (isset($invoice['status']) ? $invoice['status'] : 'N/A') . "\n"; + echo " Currency: " . (isset($invoice['currency']) ? $invoice['currency'] : 'N/A') . "\n"; + echo " Summary: " . (isset($invoice['summary']) ? $invoice['summary'] : 'N/A') . "\n"; + echo " Created: " . (isset($invoice['created_at']) ? $invoice['created_at'] : 'N/A') . "\n"; + } + } else { + echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: List invoices +echo "8. Listing invoices\n"; +echo "-------------------\n"; + +$filters = array( + 'limit' => 20, + 'offset' => 0 +); + +try { + $listResponse = $businessGateway->eInvoiceService()->listInvoices($filters); + + if ($listResponse->isSuccessful()) { + echo "✓ Invoice list retrieved successfully\n"; + echo " Limit: 20 invoices\n"; + + $listData = $listResponse->getDecodeResponse(); + if (isset($listData['data']) && is_array($listData['data'])) { + echo " Found " . count($listData['data']) . " invoices\n"; + + // Display first few invoices + $invoices = array_slice($listData['data'], 0, 3); + foreach ($invoices as $invoice) { + $id = isset($invoice['id']) ? $invoice['id'] : 'Unknown'; + $status = isset($invoice['status']) ? $invoice['status'] : 'Unknown'; + $currency = isset($invoice['currency']) ? $invoice['currency'] : 'Unknown'; + echo " - " . $id . " (Status: " . $status . ", Currency: " . $currency . ")\n"; + } + + if (count($listData['data']) > 3) { + echo " ... and " . (count($listData['data']) - 3) . " more\n"; + } + } + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 9: Delete invoice +echo "9. Deleting invoice\n"; +echo "-------------------\n"; + +$invoiceToDelete = 'FPBIV-DELETE-' . time(); // Use a test invoice ID + +try { + $deleteResponse = $businessGateway->eInvoiceService()->deleteInvoice($invoiceToDelete); + + if ($deleteResponse->isSuccessful()) { + echo "✓ Invoice deleted successfully\n"; + echo " Deleted Invoice ID: " . $invoiceToDelete . "\n"; + } else { + echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 10: Handle invoice status via pingbacks (documentation example) +echo "10. Invoice status handling via pingbacks\n"; +echo "-----------------------------------------\n"; + +echo "✓ Invoice status changes are handled via pingbacks\n"; +echo " Pingback example from API documentation:\n"; +echo " {\n"; +echo " \"event\": \"invoice.status.updated\",\n"; +echo " \"invoice\": {\n"; +echo " \"status\": \"void\",\n"; +echo " \"id\": \"FPBIV-250616-3UHJ\"\n"; +echo " }\n"; +echo " }\n"; +echo " \n"; +echo " Available invoice statuses include:\n"; +echo " - draft: Invoice is in draft status\n"; +echo " - sent: Invoice has been sent to customer\n"; +echo " - paid: Invoice has been paid\n"; +echo " - void: Invoice has been voided/cancelled\n"; +echo " - overdue: Invoice payment is overdue\n"; +echo " \n"; +echo " Status changes are automatically communicated via pingbacks\n"; +echo " to your configured pingback URL.\n"; '', + 'privateKey' => '', + 'isTest' => 1, +)); + +echo "FasterPay E-Invoice API Examples\n"; +echo "=================================\n\n"; + +// Example 1: Create a new e-invoice +echo "1. Creating a new e-invoice\n"; +echo "---------------------------\n"; + +$invoiceData = array( + 'currency' => 'USD', + 'summary' => 'Website development project invoice', + 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => 'CT-250527-AZARCIJE', + 'items' => array( + array( + 'price' => 2500.00, + 'quantity' => 1, + 'name' => 'Website Development Services', + 'description' => 'Complete website development with responsive design' + ), + array( + 'price' => 99.99, + 'quantity' => 12, + 'name' => 'Monthly Hosting Package', + 'description' => 'Premium hosting service for 12 months' + ) + ) +); + +try { + $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceData); + + if ($invoiceResponse->isSuccessful()) { + echo "✓ E-invoice created successfully\n"; + $responseData = $invoiceResponse->getDecodeResponse(); + $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Invoice Number: " . $invoiceData['number'] . "\n"; + echo " Currency: " . $invoiceData['currency'] . "\n"; + echo " Items: " . count($invoiceData['items']) . "\n"; + } else { + echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 2: Create template +echo "2. Creating invoice template\n"; +echo "----------------------------\n"; + +$templateData = array( + 'name' => 'Professional Template', + 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', + 'colors' => array( + 'primary' => '#2563eb', + 'secondary' => '#f8fafc' + ), + 'localized_address' => array( + 'address_line1' => '123 Business Avenue', + 'locality' => 'San Francisco', + 'administrative_area' => 'CA', + 'postal_code' => '94105' + ), + 'country_code' => 'US' +); + +try { + $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); + + if ($templateResponse->isSuccessful()) { + echo "✓ Invoice template created successfully\n"; + $responseData = $templateResponse->getDecodeResponse(); + $templateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-' . time(); + echo " Template ID: " . $templateId . "\n"; + echo " Name: " . $templateData['name'] . "\n"; + echo " Primary Color: " . $templateData['colors']['primary'] . "\n"; + } else { + echo "✗ Error: " . $templateResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 3: Create tax +echo "3. Creating tax configuration\n"; +echo "-----------------------------\n"; + +$taxData = array( + 'name' => 'Sales Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% sales tax rate' +); + +try { + $taxResponse = $businessGateway->eInvoiceTaxService()->createTax($taxData); + + if ($taxResponse->isSuccessful()) { + echo "✓ Tax created successfully\n"; + $responseData = $taxResponse->getDecodeResponse(); + $taxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-' . time(); + echo " Tax ID: " . $taxId . "\n"; + echo " Name: " . $taxData['name'] . "\n"; + echo " Type: " . $taxData['type'] . "\n"; + echo " Rate: " . ($taxData['value'] * 100) . "%\n"; + } else { + echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4: Create discount +echo "4. Creating discount offer\n"; +echo "--------------------------\n"; + +$discountData = array( + 'name' => 'Early Bird Discount', + 'type' => 'flat', + 'value' => 50.0, + 'currency' => 'USD', + 'description' => '$50 discount for early payment' +); + +try { + $discountResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($discountData); + + if ($discountResponse->isSuccessful()) { + echo "✓ Discount created successfully\n"; + $responseData = $discountResponse->getDecodeResponse(); + $discountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-' . time(); + echo " Discount ID: " . $discountId . "\n"; + echo " Name: " . $discountData['name'] . "\n"; + echo " Value: $" . $discountData['value'] . " " . $discountData['currency'] . "\n"; + } else { + echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 5: Create product +echo "5. Creating product\n"; +echo "-------------------\n"; + +$productData = array( + 'sku' => 'WEB-DEV-001', + 'type' => 'digital', + 'name' => 'Website Development Package', + 'description' => 'Complete website development with modern responsive design', + 'prices' => array( + array( + 'price' => 2500.00, + 'currency' => 'USD' + ) + ) +); + +try { + $productResponse = $businessGateway->eInvoiceProductService()->createProduct($productData); + + if ($productResponse->isSuccessful()) { + echo "✓ Product created successfully\n"; + $responseData = $productResponse->getDecodeResponse(); + $productId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-' . time(); + echo " Product ID: " . $productId . "\n"; + echo " SKU: " . $productData['sku'] . "\n"; + echo " Name: " . $productData['name'] . "\n"; + echo " Type: " . $productData['type'] . "\n"; + } else { + echo "✗ Error: " . $productResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 6: Send invoice +echo "6. Sending invoice to customer\n"; +echo "------------------------------\n"; + +$invoiceId = isset($invoiceId) ? $invoiceId : 'FPBIV-' . time(); +$sendParams = array( + 'method' => 'email', + 'email' => 'customer@example.com', + 'subject' => 'Invoice ' . (isset($invoiceData['number']) ? $invoiceData['number'] : 'INV-001') . ' from Your Company', + 'message' => 'Dear Customer, please find attached your invoice. Payment is due within 30 days.', + 'copy_sender' => true +); + +try { + $sendResponse = $businessGateway->eInvoiceService()->sendInvoice($invoiceId, $sendParams); + + if ($sendResponse->isSuccessful()) { + echo "✓ Invoice sent successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Sent to: " . $sendParams['email'] . "\n"; + echo " Method: " . $sendParams['method'] . "\n"; + } else { + echo "✗ Error: " . $sendResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: Mark invoice as paid +echo "7. Marking invoice as paid\n"; +echo "--------------------------\n"; + +$paymentData = array( + 'amount' => 2599.99, + 'payment_date' => date('Y-m-d'), + 'payment_method' => 'bank_transfer', + 'reference' => 'TXN-' . time(), + 'notes' => 'Payment received via bank transfer' +); + +try { + $paidResponse = $businessGateway->eInvoiceService()->markAsPaid($invoiceId, $paymentData); + + if ($paidResponse->isSuccessful()) { + echo "✓ Invoice marked as paid successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Amount: $" . number_format($paymentData['amount'], 2) . "\n"; + echo " Payment Date: " . $paymentData['payment_date'] . "\n"; + echo " Method: " . $paymentData['payment_method'] . "\n"; + } else { + echo "✗ Error: " . $paidResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: List invoices +echo "8. Listing invoices\n"; +echo "-------------------\n"; + +$filters = array( + 'limit' => 20, + 'offset' => 0 +); + +try { + $listResponse = $businessGateway->eInvoiceService()->listInvoices($filters); + + if ($listResponse->isSuccessful()) { + echo "✓ Invoice list retrieved successfully\n"; + echo " Limit: 20 invoices\n"; + + $listData = $listResponse->getDecodeResponse(); + if (isset($listData['data']) && is_array($listData['data'])) { + echo " Found " . count($listData['data']) . " invoices\n"; + + // Display first few invoices + $invoices = array_slice($listData['data'], 0, 3); + foreach ($invoices as $invoice) { + $id = isset($invoice['id']) ? $invoice['id'] : 'Unknown'; + $status = isset($invoice['status']) ? $invoice['status'] : 'Unknown'; + $currency = isset($invoice['currency']) ? $invoice['currency'] : 'Unknown'; + echo " - " . $id . " (Status: " . $status . ", Currency: " . $currency . ")\n"; + } + + if (count($listData['data']) > 3) { + echo " ... and " . (count($listData['data']) - 3) . " more\n"; + } + } + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 9: Get invoice status +echo "9. Getting invoice status\n"; +echo "-------------------------\n"; + +try { + $statusResponse = $businessGateway->eInvoiceService()->getInvoiceStatus($invoiceId); + + if ($statusResponse->isSuccessful()) { + echo "✓ Invoice status retrieved successfully\n"; + $statusData = $statusResponse->getDecodeResponse(); + echo " Invoice ID: " . $invoiceId . "\n"; + + if (isset($statusData['data'])) { + $status = $statusData['data']; + echo " Status: " . (isset($status['status']) ? $status['status'] : 'N/A') . "\n"; + echo " Last updated: " . (isset($status['updated_at']) ? $status['updated_at'] : date('Y-m-d H:i:s')) . "\n"; + } + } else { + echo "✗ Error: " . $statusResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 10: Cancel invoice +echo "10. Cancelling invoice\n"; +echo "----------------------\n"; + +$cancelParams = array( + 'reason' => 'Customer requested cancellation' +); + +try { + $cancelResponse = $businessGateway->eInvoiceService()->cancelInvoice($invoiceId, $cancelParams); + + if ($cancelResponse->isSuccessful()) { + echo "✓ Invoice cancelled successfully\n"; + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Reason: " . $cancelParams['reason'] . "\n"; + } else { + echo "✗ Error: " . $cancelResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\nE-Invoice API examples completed!\n"; +echo "Use cases:\n"; +echo "• Automated billing and invoicing\n"; +echo "• Recurring subscription billing\n"; +echo "• Professional invoice generation\n"; +echo "• Payment tracking and reminders\n"; +echo "• Financial reporting and analytics\n"; +echo "• Multi-currency invoicing\n"; +echo "• Tax compliance and reporting\n"; +echo "• Customer payment portal integration\n"; \ No newline at end of file diff --git a/lib/FasterPay/HttpClient.php b/lib/FasterPay/HttpClient.php index e476352..cc3a189 100644 --- a/lib/FasterPay/HttpClient.php +++ b/lib/FasterPay/HttpClient.php @@ -38,6 +38,11 @@ public function post($endpoint, array $params = [], array $headers = []) return $this->call($endpoint, $params, 'POST', $headers); } + public function postMultipart($endpoint, array $params = [], array $headers = []) + { + return $this->call($endpoint, $params, 'POST_MULTIPART', $headers); + } + public function put($endpoint, array $params = [], array $headers = []) { return $this->call($endpoint, $params, 'PUT', $headers); @@ -48,30 +53,53 @@ public function delete($endpoint, array $params = [], array $headers = []) return $this->call($endpoint, $params, 'DELETE', $headers); } - private function call($endpoint, array $params = [], $method, array $headers = []) { $ch = $this->init(); $header = array_merge($this->header, $headers); - curl_setopt($ch, CURLOPT_HTTPHEADER, $header); switch (strtoupper($method)) { case 'POST': + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); if (!empty($params)) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); } + curl_setopt($ch, CURLOPT_POST, true); + break; + + case 'POST_MULTIPART': + $multipartHeaders = []; + foreach ($header as $h) { + if (stripos($h, 'Content-Type:') !== 0) { + $multipartHeaders[] = $h; + } + } + curl_setopt($ch, CURLOPT_HTTPHEADER, $multipartHeaders); + + if (!empty($params)) { + $multipartData = $this->buildMultipartData($params); + curl_setopt($ch, CURLOPT_POSTFIELDS, $multipartData); + } + + curl_setopt($ch, CURLOPT_POST, true); + break; + case 'PUT': case 'DELETE': + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_HTTPGET, false); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); + if (!empty($params)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); + } break; + case 'GET': + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); if (!empty($params)) { $endpoint .= '?' . http_build_query($params); } - curl_setopt($ch, CURLOPT_POST, false); curl_setopt($ch, CURLOPT_HTTPGET, true); break; @@ -79,10 +107,7 @@ private function call($endpoint, array $params = [], $method, array $headers = [ curl_setopt($ch, CURLOPT_URL, $endpoint); - $response = curl_exec($ch); - - $info = curl_getinfo($ch); curl_close($ch); @@ -92,4 +117,32 @@ private function call($endpoint, array $params = [], $method, array $headers = [ ]; } + private function buildMultipartData(array $data, $prefix = '') + { + $result = []; + + foreach ($data as $key => $value) { + $fieldName = $prefix ? $prefix . '[' . $key . ']' : $key; + + if (is_array($value)) { + $nestedData = $this->buildMultipartData($value, $fieldName); + $result = array_merge($result, $nestedData); + } elseif (is_string($value) && substr($value, 0, 1) === '@') { + if (class_exists('CURLFile')) { + $filePath = substr($value, 1); + if (file_exists($filePath)) { + $result[$fieldName] = new CURLFile($filePath); + } else { + $result[$fieldName] = $value; + } + } else { + $result[$fieldName] = $value; + } + } else { + $result[$fieldName] = (string) $value; + } + } + + return $result; + } } diff --git a/lib/FasterPay/Services/Business/Contact.php b/lib/FasterPay/Services/Business/Contact.php index 4e04a7e..3365cb7 100644 --- a/lib/FasterPay/Services/Business/Contact.php +++ b/lib/FasterPay/Services/Business/Contact.php @@ -10,302 +10,47 @@ class Contact extends GeneralService { protected $endpoint = 'api/external/contacts'; - /** - * Create a new contact - * - * @param array $params Contact parameters - * @return GeneralResponse - * @throws Exception - */ public function createContact(array $params = []) { - $this->validateContactParams($params); - $endpoint = $this->httpService->getEndPoint($this->endpoint); - $response = $this->httpService->getHttpClient()->post($endpoint, $params); - return new GeneralResponse($response); } - /** - * Get contact details - * - * @param string $contactId Contact ID - * @return GeneralResponse - * @throws Exception - */ public function getContact($contactId = '') { if (empty($contactId)) { throw new Exception('Contact ID is required'); } - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId); - $response = $this->httpService->getHttpClient()->get($endpoint); - return new GeneralResponse($response); } - /** - * Update contact - * - * @param string $contactId Contact ID - * @param array $params Updated contact parameters - * @return GeneralResponse - * @throws Exception - */ public function updateContact($contactId = '', array $params = []) { if (empty($contactId)) { throw new Exception('Contact ID is required'); } - - $this->validateContactParams($params, false); - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId); - $response = $this->httpService->getHttpClient()->put($endpoint, $params); - return new GeneralResponse($response); } - /** - * Delete contact - * - * @param string $contactId Contact ID - * @return GeneralResponse - * @throws Exception - */ public function deleteContact($contactId = '') { if (empty($contactId)) { throw new Exception('Contact ID is required'); } - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId); - $response = $this->httpService->getHttpClient()->delete($endpoint); - return new GeneralResponse($response); } - /** - * List contacts - * - * @param array $filters Optional filters (limit, offset, type, status, etc.) - * @return GeneralResponse - */ public function listContacts(array $filters = []) { $endpoint = $this->httpService->getEndPoint($this->endpoint); - $response = $this->httpService->getHttpClient()->get($endpoint, $filters); - - return new GeneralResponse($response); - } - - /** - * Search contacts - * - * @param array $searchParams Search parameters (name, email, phone, etc.) - * @return GeneralResponse - * @throws Exception - */ - public function searchContacts(array $searchParams = []) - { - if (empty($searchParams)) { - throw new Exception('Search parameters are required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/search'); - - $response = $this->httpService->getHttpClient()->post($endpoint, $searchParams); - - return new GeneralResponse($response); - } - - /** - * Get contact by email - * - * @param string $email Email address - * @return GeneralResponse - * @throws Exception - */ - public function getContactByEmail($email = '') - { - if (empty($email)) { - throw new Exception('Email address is required'); - } - - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { - throw new Exception('Invalid email format'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/email/' . urlencode($email)); - - $response = $this->httpService->getHttpClient()->get($endpoint); - - return new GeneralResponse($response); - } - - /** - * Get contact by phone - * - * @param string $phone Phone number - * @return GeneralResponse - * @throws Exception - */ - public function getContactByPhone($phone = '') - { - if (empty($phone)) { - throw new Exception('Phone number is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/phone/' . urlencode($phone)); - - $response = $this->httpService->getHttpClient()->get($endpoint); - - return new GeneralResponse($response); - } - - /** - * Add address to contact - * - * @param string $contactId Contact ID - * @param array $addressData Address data - * @return GeneralResponse - * @throws Exception - */ - public function addContactAddress($contactId = '', array $addressData = []) - { - if (empty($contactId)) { - throw new Exception('Contact ID is required'); - } - - if (empty($addressData)) { - throw new Exception('Address data is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId . '/address'); - - $response = $this->httpService->getHttpClient()->post($endpoint, $addressData); - - return new GeneralResponse($response); - } - - /** - * Update contact address - * - * @param string $contactId Contact ID - * @param string $addressId Address ID - * @param array $addressData Updated address data - * @return GeneralResponse - * @throws Exception - */ - public function updateContactAddress($contactId = '', $addressId = '', array $addressData = []) - { - if (empty($contactId)) { - throw new Exception('Contact ID is required'); - } - - if (empty($addressId)) { - throw new Exception('Address ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId . '/address/' . $addressId); - - $response = $this->httpService->getHttpClient()->put($endpoint, $addressData); - - return new GeneralResponse($response); - } - - /** - * Remove address from contact - * - * @param string $contactId Contact ID - * @param string $addressId Address ID - * @return GeneralResponse - * @throws Exception - */ - public function removeContactAddress($contactId = '', $addressId = '') - { - if (empty($contactId)) { - throw new Exception('Contact ID is required'); - } - - if (empty($addressId)) { - throw new Exception('Address ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId . '/address/' . $addressId); - - $response = $this->httpService->getHttpClient()->delete($endpoint); - - return new GeneralResponse($response); - } - - /** - * Get contact addresses - * - * @param string $contactId Contact ID - * @return GeneralResponse - * @throws Exception - */ - public function getContactAddresses($contactId = '') - { - if (empty($contactId)) { - throw new Exception('Contact ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $contactId . '/addresses'); - - $response = $this->httpService->getHttpClient()->get($endpoint); - return new GeneralResponse($response); } - - /** - * Validate contact parameters - * - * @param array $params Contact parameters - * @param bool $requireAll Whether all fields are required (for create vs update) - * @throws Exception - */ - private function validateContactParams(array $params, $requireAll = true) - { - if ($requireAll) { - if (empty($params['first_name']) && empty($params['name'])) { - throw new Exception('First name or name is required'); - } - - if (empty($params['email']) && empty($params['phone'])) { - throw new Exception('Email or phone number is required'); - } - } - - // Validate email format if provided - if (!empty($params['email']) && !filter_var($params['email'], FILTER_VALIDATE_EMAIL)) { - throw new Exception('Invalid email format'); - } - - // Validate phone format if provided (basic validation) - if (!empty($params['phone'])) { - $phone = preg_replace('/[^\d+]/', '', $params['phone']); - if (strlen($phone) < 7 || strlen($phone) > 15) { - throw new Exception('Invalid phone number format'); - } - } - - // Validate phone_country_code if provided - if (!empty($params['phone_country_code']) && strlen($params['phone_country_code']) !== 2) { - throw new Exception('Phone country code must be 2 characters (ISO 3166-1 alpha-2)'); - } - - // Validate country if provided - if (!empty($params['country']) && strlen($params['country']) !== 2) { - throw new Exception('Country must be 2 characters (ISO 3166-1 alpha-2)'); - } - } -} \ No newline at end of file +} diff --git a/lib/FasterPay/Services/Business/EInvoice/Invoice.php b/lib/FasterPay/Services/Business/EInvoice/Invoice.php index b58506f..c50440b 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Invoice.php +++ b/lib/FasterPay/Services/Business/EInvoice/Invoice.php @@ -15,40 +15,13 @@ class Invoice extends GeneralService * * @param array $params E-invoice parameters * @return GeneralResponse - * @throws Exception */ public function createInvoice(array $params = []) { - if (empty($params['contact_id'])) { - throw new Exception('Contact ID is required'); - } - - if (empty($params['currency'])) { - throw new Exception('Currency is required'); - } - - if (empty($params['items']) || !is_array($params['items'])) { - throw new Exception('Invoice items are required'); - } - - // Validate currency format - if (strlen($params['currency']) !== 3) { - throw new Exception('Currency must be 3 characters (ISO 4217)'); - } - - // Validate items - foreach ($params['items'] as $item) { - if (!isset($item['price']) || !is_numeric($item['price'])) { - throw new Exception('Each item must have a numeric price'); - } - if (!isset($item['quantity']) || !is_numeric($item['quantity']) || $item['quantity'] <= 0) { - throw new Exception('Each item must have a positive quantity'); - } - } - $endpoint = $this->httpService->getEndPoint($this->endpoint); - $response = $this->httpService->getHttpClient()->post($endpoint, $params); + // For multipart/form-data requests + $response = $this->httpService->getHttpClient()->postMultipart($endpoint, $params); return new GeneralResponse($response); } @@ -87,11 +60,13 @@ public function updateInvoice($invoiceId = '', array $params = []) throw new Exception('Invoice ID is required'); } - $this->validateInvoiceParams($params, false); - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId); - $response = $this->httpService->getHttpClient()->put($endpoint, $params); + // Add _method=PUT for update via POST + $params['_method'] = 'PUT'; + + // For multipart/form-data requests + $response = $this->httpService->getHttpClient()->postMultipart($endpoint, $params); return new GeneralResponse($response); } @@ -119,7 +94,7 @@ public function deleteInvoice($invoiceId = '') /** * List e-invoices * - * @param array $filters Optional filters (limit, offset, status, date_from, date_to, etc.) + * @param array $filters Optional filters * @return GeneralResponse */ public function listInvoices(array $filters = []) @@ -135,7 +110,7 @@ public function listInvoices(array $filters = []) * Send e-invoice * * @param string $invoiceId Invoice ID - * @param array $sendParams Send parameters (email, method, etc.) + * @param array $sendParams Send parameters * @return GeneralResponse * @throws Exception */ @@ -156,278 +131,19 @@ public function sendInvoice($invoiceId = '', array $sendParams = []) * Download e-invoice PDF * * @param string $invoiceId Invoice ID - * @param array $options Download options (format, template, etc.) - * @return GeneralResponse - * @throws Exception - */ - public function downloadInvoice($invoiceId = '', array $options = []) - { - if (empty($invoiceId)) { - throw new Exception('Invoice ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/download'); - - $response = $this->httpService->getHttpClient()->get($endpoint, $options); - - return new GeneralResponse($response); - } - - /** - * Get invoice status - * - * @param string $invoiceId Invoice ID - * @return GeneralResponse - * @throws Exception - */ - public function getInvoiceStatus($invoiceId = '') - { - if (empty($invoiceId)) { - throw new Exception('Invoice ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/status'); - - $response = $this->httpService->getHttpClient()->get($endpoint); - - return new GeneralResponse($response); - } - - /** - * Cancel e-invoice - * - * @param string $invoiceId Invoice ID - * @param array $cancelParams Cancellation parameters (reason, etc.) - * @return GeneralResponse - * @throws Exception - */ - public function cancelInvoice($invoiceId = '', array $cancelParams = []) - { - if (empty($invoiceId)) { - throw new Exception('Invoice ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/cancel'); - - $response = $this->httpService->getHttpClient()->post($endpoint, $cancelParams); - - return new GeneralResponse($response); - } - - /** - * Mark invoice as paid - * - * @param string $invoiceId Invoice ID - * @param array $paymentData Payment data (amount, date, method, etc.) - * @return GeneralResponse + * @param array $options Download options + * @return array Raw file response array with 'response' and 'httpCode' * @throws Exception */ - public function markAsPaid($invoiceId = '', array $paymentData = []) + public function downloadInvoicePdf($invoiceId = '', array $options = []) { if (empty($invoiceId)) { throw new Exception('Invoice ID is required'); } - if (empty($paymentData['amount'])) { - throw new Exception('Payment amount is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/paid'); - - $response = $this->httpService->getHttpClient()->post($endpoint, $paymentData); - - return new GeneralResponse($response); - } - - /** - * Add item to invoice - * - * @param string $invoiceId Invoice ID - * @param array $itemData Item data - * @return GeneralResponse - * @throws Exception - */ - public function addInvoiceItem($invoiceId = '', array $itemData = []) - { - if (empty($invoiceId)) { - throw new Exception('Invoice ID is required'); - } - - $this->validateInvoiceItem($itemData); - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/items'); - - $response = $this->httpService->getHttpClient()->post($endpoint, $itemData); - - return new GeneralResponse($response); - } + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/pdf'); - /** - * Update invoice item - * - * @param string $invoiceId Invoice ID - * @param string $itemId Item ID - * @param array $itemData Updated item data - * @return GeneralResponse - * @throws Exception - */ - public function updateInvoiceItem($invoiceId = '', $itemId = '', array $itemData = []) - { - if (empty($invoiceId)) { - throw new Exception('Invoice ID is required'); - } - - if (empty($itemId)) { - throw new Exception('Item ID is required'); - } - - $this->validateInvoiceItem($itemData, false); - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/items/' . $itemId); - - $response = $this->httpService->getHttpClient()->put($endpoint, $itemData); - - return new GeneralResponse($response); - } - - /** - * Remove item from invoice - * - * @param string $invoiceId Invoice ID - * @param string $itemId Item ID - * @return GeneralResponse - * @throws Exception - */ - public function removeInvoiceItem($invoiceId = '', $itemId = '') - { - if (empty($invoiceId)) { - throw new Exception('Invoice ID is required'); - } - - if (empty($itemId)) { - throw new Exception('Item ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/items/' . $itemId); - - $response = $this->httpService->getHttpClient()->delete($endpoint); - - return new GeneralResponse($response); - } - - /** - * Search invoices - * - * @param array $searchParams Search parameters - * @return GeneralResponse - * @throws Exception - */ - public function searchInvoices(array $searchParams = []) - { - if (empty($searchParams)) { - throw new Exception('Search parameters are required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/search'); - - $response = $this->httpService->getHttpClient()->post($endpoint, $searchParams); - - return new GeneralResponse($response); - } - - /** - * Validate invoice parameters - * - * @param array $params Invoice parameters - * @param bool $requireAll Whether all fields are required (for create vs update) - * @throws Exception - */ - private function validateInvoiceParams(array $params, $requireAll = true) - { - if ($requireAll) { - if (empty($params['customer_id']) && empty($params['customer'])) { - throw new Exception('Customer ID or customer details are required'); - } - - if (empty($params['items']) || !is_array($params['items'])) { - throw new Exception('Invoice items are required'); - } - - if (empty($params['due_date'])) { - throw new Exception('Due date is required'); - } - } - - // Validate due date format if provided - if (!empty($params['due_date'])) { - $date = \DateTime::createFromFormat('Y-m-d', $params['due_date']); - if (!$date || $date->format('Y-m-d') !== $params['due_date']) { - throw new Exception('Invalid due date format. Use YYYY-MM-DD'); - } - } - - // Validate currency if provided - if (!empty($params['currency']) && strlen($params['currency']) !== 3) { - throw new Exception('Currency must be 3 characters (ISO 4217)'); - } - - // Validate status if provided - if (!empty($params['status'])) { - $validStatuses = ['draft', 'sent', 'paid', 'cancelled', 'overdue']; - if (!in_array($params['status'], $validStatuses)) { - throw new Exception('Invalid status. Must be one of: ' . implode(', ', $validStatuses)); - } - } - - // Validate items if provided - if (!empty($params['items']) && is_array($params['items'])) { - foreach ($params['items'] as $item) { - $this->validateInvoiceItem($item); - } - } - } - - /** - * Validate invoice item - * - * @param array $item Item data - * @param bool $requireAll Whether all fields are required - * @throws Exception - */ - private function validateInvoiceItem(array $item, $requireAll = true) - { - if ($requireAll) { - if (empty($item['description'])) { - throw new Exception('Item description is required'); - } - - if (empty($item['quantity']) || !is_numeric($item['quantity'])) { - throw new Exception('Item quantity is required and must be numeric'); - } - - if (empty($item['unit_price']) || !is_numeric($item['unit_price'])) { - throw new Exception('Item unit price is required and must be numeric'); - } - } - - // Validate quantity if provided - if (!empty($item['quantity']) && (!is_numeric($item['quantity']) || $item['quantity'] <= 0)) { - throw new Exception('Item quantity must be a positive number'); - } - - // Validate unit price if provided - if (!empty($item['unit_price']) && (!is_numeric($item['unit_price']) || $item['unit_price'] < 0)) { - throw new Exception('Item unit price must be a non-negative number'); - } - - // Validate tax rate if provided - if (!empty($item['tax_rate']) && (!is_numeric($item['tax_rate']) || $item['tax_rate'] < 0 || $item['tax_rate'] > 100)) { - throw new Exception('Item tax rate must be between 0 and 100'); - } - - // Validate discount if provided - if (!empty($item['discount']) && (!is_numeric($item['discount']) || $item['discount'] < 0)) { - throw new Exception('Item discount must be a non-negative number'); - } + // Return raw response for file download + return $this->httpService->getHttpClient()->get($endpoint, $options); } } \ No newline at end of file From 1f60f5daa40104fa7995281066251e4d2a75a21a Mon Sep 17 00:00:00 2001 From: James Date: Tue, 5 Aug 2025 19:14:37 +0700 Subject: [PATCH 03/20] update --- code-samples/business/e-invoice/template.php | 261 ++++++++++++++++-- lib/FasterPay/BusinessGateway.php | 2 +- lib/FasterPay/Config.php | 2 +- lib/FasterPay/HttpClient.php | 178 ++++++++---- .../Services/Business/EInvoice/Template.php | 56 +--- 5 files changed, 360 insertions(+), 139 deletions(-) diff --git a/code-samples/business/e-invoice/template.php b/code-samples/business/e-invoice/template.php index 19ddc5f..50e6dc7 100644 --- a/code-samples/business/e-invoice/template.php +++ b/code-samples/business/e-invoice/template.php @@ -17,7 +17,6 @@ $templateData = [ 'name' => 'Professional Template', - 'address' => null, 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', 'colors' => [ 'primary' => '#2563eb', @@ -36,7 +35,7 @@ $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); if ($templateResponse->isSuccessful()) { - echo "✓ Invoice template created successfully\n"; + echo "Template created successfully\n"; $responseData = $templateResponse->getDecodeResponse(); $templateId = $responseData['data']['id'] ?? 'IT-' . time(); echo " Template ID: $templateId\n"; @@ -45,10 +44,94 @@ echo " Address: {$templateData['localized_address']['address_line1']}, {$templateData['localized_address']['locality']}\n"; echo " Full Address: " . ($responseData['data']['full_address'] ?? 'Generated automatically') . "\n"; } else { - echo "✗ Error: " . $templateResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $templateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 4.5: Update template with logo +echo "4.5 Updating template with logo\n"; +echo "--------------------------------\n"; + +$updateWithLogoData = [ + 'footer' => 'Updated template with new branding and logo!', + 'colors' => [ + 'primary' => '#7c2d12', + 'secondary' => '#fef7ed' + ], + 'logo' => '/path/to/updated-logo.jpg' // File path provided directly in params +]; + +try { + // Note: In real implementation, provide actual logo file path in params['logo'] + // The service automatically detects file fields and uses multipart upload with _method=PUT + + // For demo purposes, update without logo + $demoUpdateData = $updateWithLogoData; + unset($demoUpdateData['logo']); // Remove for demo + $updateLogoResponse = $businessGateway->eInvoiceTemplateService()->updateTemplate($templateId, $demoUpdateData); + + if ($updateLogoResponse->isSuccessful()) { + echo "Template with logo updated successfully\n"; + echo " Updated footer and branding colors\n"; + echo " Logo: File would be uploaded automatically if 'logo' field contains file path\n"; + echo " Usage: \$params['logo'] = '/path/to/new-file.jpg'\n"; + echo " Method: Automatically uses POST + _method=PUT for file uploads\n"; + } else { + echo "Error: " . $updateLogoResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 1.5: Create template with logo upload +echo "1.5 Creating template with logo\n"; +echo "--------------------------------\n"; + +$templateWithLogoData = [ + 'name' => 'Branded Logo Template', + 'footer' => 'Professional template with company logo', + 'colors' => [ + 'primary' => '#e11d48', + 'secondary' => '#fdf2f8' + ], + 'localized_address' => [ + 'address_line1' => '789 Logo Street', + 'locality' => 'Design City', + 'administrative_area' => 'CA', + 'postal_code' => '90210' + ], + 'country_code' => 'US', + 'logo' => '/path/to/company-logo.png' // File path provided directly in params +]; + +try { + // Note: In real implementation, provide actual logo file path in params['logo'] + // The service automatically detects file fields and uses multipart upload + + // For demo purposes, create without logo + $demoData = $templateWithLogoData; + unset($demoData['logo']); // Remove for demo + $logoResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($demoData); + + if ($logoResponse->isSuccessful()) { + echo "Template with logo created successfully\n"; + $responseData = $logoResponse->getDecodeResponse(); + $logoTemplateId = $responseData['data']['id'] ?? 'IT-LOGO-' . time(); + echo " Template ID: $logoTemplateId\n"; + echo " Name: {$templateWithLogoData['name']}\n"; + echo " Logo: File would be uploaded automatically if 'logo' field contains file path\n"; + echo " Usage: \$params['logo'] = '/path/to/file.png'\n"; + } else { + echo "Error: " . $logoResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -59,7 +142,7 @@ $brandedTemplateData = [ 'name' => 'Company Branded Template', - 'footer' => 'Powered by YourCompany © 2024 | www.yourcompany.com', + 'footer' => 'Powered by YourCompany 2024 | www.yourcompany.com', 'colors' => [ 'primary' => '#ff6b35', 'secondary' => '#f7f3f0' @@ -78,17 +161,17 @@ $brandedResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($brandedTemplateData); if ($brandedResponse->isSuccessful()) { - echo "✓ Branded template created successfully\n"; + echo "Branded template created successfully\n"; $responseData = $brandedResponse->getDecodeResponse(); $brandedTemplateId = $responseData['data']['id'] ?? 'IT-BRAND-' . time(); echo " Template ID: $brandedTemplateId\n"; echo " Brand Colors: {$brandedTemplateData['colors']['primary']} / {$brandedTemplateData['colors']['secondary']}\n"; echo " Corporate Address: {$brandedTemplateData['localized_address']['address_line1']}\n"; } else { - echo "✗ Error: " . $brandedResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $brandedResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -103,7 +186,7 @@ $detailsResponse = $businessGateway->eInvoiceTemplateService()->getTemplate($templateId); if ($detailsResponse->isSuccessful()) { - echo "✓ Template details retrieved\n"; + echo "Template details retrieved\n"; $details = $detailsResponse->getDecodeResponse(); $template = $details['data'] ?? []; @@ -111,11 +194,20 @@ echo " Name: " . ($template['name'] ?? 'N/A') . "\n"; echo " Country: " . ($template['country_code'] ?? 'N/A') . "\n"; echo " Footer: " . ($template['footer'] ?? 'N/A') . "\n"; + + if (isset($template['colors'])) { + echo " Primary Color: " . ($template['colors']['primary'] ?? 'N/A') . "\n"; + echo " Secondary Color: " . ($template['colors']['secondary'] ?? 'N/A') . "\n"; + } + + if (isset($template['full_address'])) { + echo " Full Address: " . $template['full_address'] . "\n"; + } } else { - echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -136,14 +228,14 @@ $updateResponse = $businessGateway->eInvoiceTemplateService()->updateTemplate($templateId, $updateData); if ($updateResponse->isSuccessful()) { - echo "✓ Template updated successfully\n"; + echo "Template updated successfully\n"; echo " Updated primary color to: {$updateData['colors']['primary']}\n"; echo " Updated footer\n"; } else { - echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -152,15 +244,22 @@ echo "5. Listing all templates\n"; echo "------------------------\n"; +$listFilters = [ + 'page' => 1, + 'per_page' => 10 +]; + try { - $listResponse = $businessGateway->eInvoiceTemplateService()->listTemplates(); + $listResponse = $businessGateway->eInvoiceTemplateService()->listTemplates($listFilters); if ($listResponse->isSuccessful()) { - echo "✓ Templates list retrieved\n"; + echo "Templates list retrieved\n"; $listData = $listResponse->getDecodeResponse(); $templates = $listData['data']['data'] ?? []; echo " Total templates: " . count($templates) . "\n"; + echo " Current page: " . ($listData['data']['current_page'] ?? 1) . "\n"; + echo " Per page: " . ($listData['data']['per_page'] ?? 10) . "\n"; if (!empty($templates)) { echo " Templates:\n"; @@ -172,10 +271,10 @@ } } } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -203,24 +302,132 @@ $ukResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($ukTemplateData); if ($ukResponse->isSuccessful()) { - echo "✓ UK template created successfully\n"; + echo "UK template created successfully\n"; $responseData = $ukResponse->getDecodeResponse(); $ukTemplateId = $responseData['data']['id'] ?? 'IT-UK-' . time(); echo " Template ID: $ukTemplateId\n"; echo " Country: GB (United Kingdom)\n"; echo " Address format: UK postal code format\n"; } else { - echo "✗ Error: " . $ukResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $ukResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: Create template with generic address +echo "7. Creating template with generic address\n"; +echo "-----------------------------------------\n"; + +$genericTemplateData = [ + 'name' => 'Generic Address Template', + 'address' => '789 International Blvd, Global City, GC 12345, World', + 'footer' => 'International Business Solutions', + 'colors' => [ + 'primary' => '#7c3aed', + 'secondary' => '#f3e8ff' + ], + 'country_code' => 'XX' +]; + +try { + $genericResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($genericTemplateData); + + if ($genericResponse->isSuccessful()) { + echo "Generic template created successfully\n"; + $responseData = $genericResponse->getDecodeResponse(); + $genericTemplateId = $responseData['data']['id'] ?? 'IT-GENERIC-' . time(); + echo " Template ID: $genericTemplateId\n"; + echo " Generic Address: {$genericTemplateData['address']}\n"; + echo " Country: {$genericTemplateData['country_code']}\n"; + } else { + echo "Error: " . $genericResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: Search templates with filters +echo "8. Searching templates with name filter\n"; +echo "---------------------------------------\n"; + +$searchFilters = [ + 'page' => 1, + 'per_page' => 5, + 'filter' => [ + 'name' => 'Professional' + ] +]; + +try { + $searchResponse = $businessGateway->eInvoiceTemplateService()->listTemplates($searchFilters); + + if ($searchResponse->isSuccessful()) { + echo "Template search completed\n"; + $searchData = $searchResponse->getDecodeResponse(); + $searchResults = $searchData['data']['data'] ?? []; + + echo " Search filter: name contains 'Professional'\n"; + echo " Found templates: " . count($searchResults) . "\n"; + + if (!empty($searchResults)) { + foreach ($searchResults as $template) { + $id = $template['id'] ?? 'Unknown'; + $name = $template['name'] ?? 'Unnamed'; + echo " - $name ($id)\n"; + } + } + } else { + echo "Error: " . $searchResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 9: Delete a template +echo "9. Deleting a template\n"; +echo "----------------------\n"; + +$deleteTemplateId = $ukTemplateId ?? 'IT-DELETE-' . time(); + +try { + $deleteResponse = $businessGateway->eInvoiceTemplateService()->deleteTemplate($deleteTemplateId); + + if ($deleteResponse->isSuccessful()) { + echo "Template deleted successfully\n"; + echo " Deleted Template ID: $deleteTemplateId\n"; + } else { + echo "Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\nE-Invoice Template API examples completed!\n"; echo "Use cases:\n"; -echo "• Brand-consistent invoice design\n"; -echo "• Multi-country invoice templates\n"; -echo "• Corporate identity management\n"; -echo "• Professional invoice presentation\n"; -echo "• Template reuse across invoices\n"; -echo "• Localized address formatting\n"; \ No newline at end of file +echo "- Brand-consistent invoice design\n"; +echo "- Multi-country invoice templates\n"; +echo "- Corporate identity management\n"; +echo "- Professional invoice presentation\n"; +echo "- Template reuse across invoices\n"; +echo "- Localized address formatting\n"; +echo "- Custom color schemes and branding\n"; +echo "- Template management and organization\n"; +echo "- Logo upload and branding (multipart/form-data)\n"; +echo "- Server-side validation and processing\n"; + +echo "\nMultipart Support Notes:\n"; +echo "- File auto-detection built into HttpClient - works across all services\n"; +echo "- Any field with existing file path automatically uploaded via multipart\n"; +echo "- Works with any field name (logo, image, document, attachment, etc.)\n"; +echo "- POST: Automatically uses multipart/form-data when files detected\n"; +echo "- PUT: Automatically uses POST + _method=PUT when files detected\n"; +echo "- No client-side validation - API handles all parameter validation\n"; +echo "- File detection: Non-URL strings that point to existing files\n"; +echo "- Universal: Same logic applies to all API endpoints with file support\n"; \ No newline at end of file diff --git a/lib/FasterPay/BusinessGateway.php b/lib/FasterPay/BusinessGateway.php index 77ef431..2911754 100644 --- a/lib/FasterPay/BusinessGateway.php +++ b/lib/FasterPay/BusinessGateway.php @@ -17,7 +17,7 @@ class BusinessGateway implements GatewayInterface { - const BUSINESS_API_BASE_URL = 'https://business.fasterpay.com'; + const BUSINESS_API_BASE_URL = 'https://develop.ma.fasterpay.bamboo.stuffio.com'; const BUSINESS_API_SANDBOX_BASE_URL = 'https://business.sandbox.fasterpay.com'; protected $config; diff --git a/lib/FasterPay/Config.php b/lib/FasterPay/Config.php index e5c6d3e..87267c1 100644 --- a/lib/FasterPay/Config.php +++ b/lib/FasterPay/Config.php @@ -5,7 +5,7 @@ class Config { const VERSION = '1.0.0'; - const API_BASE_URL = 'https://pay.fasterpay.com'; + const API_BASE_URL = 'https://develop.pay2.fasterpay.bamboo.stuffio.com'; const API_SANDBOX_BASE_URL = 'https://pay.sandbox.fasterpay.com'; private $publicKey = null; diff --git a/lib/FasterPay/HttpClient.php b/lib/FasterPay/HttpClient.php index cc3a189..bd895a5 100644 --- a/lib/FasterPay/HttpClient.php +++ b/lib/FasterPay/HttpClient.php @@ -33,18 +33,45 @@ public function get($endpoint, array $params = [], array $headers = []) return $this->call($endpoint, $params, 'GET', $headers); } + /** + * Send POST request with automatic multipart detection + * + * @param string $endpoint API endpoint + * @param array $params Form parameters + * @param array $headers Additional headers + * @return array + */ public function post($endpoint, array $params = [], array $headers = []) { + // Auto-detect files and use multipart if needed + $files = $this->extractFiles($params); + + if (!empty($files)) { + return $this->postMultipart($endpoint, $params, $files, $headers); + } + return $this->call($endpoint, $params, 'POST', $headers); } - public function postMultipart($endpoint, array $params = [], array $headers = []) - { - return $this->call($endpoint, $params, 'POST_MULTIPART', $headers); - } - + /** + * Send PUT request with automatic multipart detection + * Note: If files detected, uses POST with _method=PUT for multipart compatibility + * + * @param string $endpoint API endpoint + * @param array $params Form parameters + * @param array $headers Additional headers + * @return array + */ public function put($endpoint, array $params = [], array $headers = []) { + // Auto-detect files and use multipart if needed + $files = $this->extractFiles($params); + + if (!empty($files)) { + $params['_method'] = 'PUT'; + return $this->postMultipart($endpoint, $params, $files, $headers); + } + return $this->call($endpoint, $params, 'PUT', $headers); } @@ -53,50 +80,116 @@ public function delete($endpoint, array $params = [], array $headers = []) return $this->call($endpoint, $params, 'DELETE', $headers); } - private function call($endpoint, array $params = [], $method, array $headers = []) + /** + * Send multipart POST request with file uploads + * + * @param string $endpoint API endpoint + * @param array $params Form parameters + * @param array $files Array of files where key is field name and value is file path + * @param array $headers Additional headers + * @return array + */ + public function postMultipart($endpoint, array $params = [], array $files = [], array $headers = []) { $ch = $this->init(); $header = array_merge($this->header, $headers); + + // Remove Content-Type header to let cURL set it automatically for multipart + $header = array_filter($header, function($h) { + return stripos($h, 'Content-Type:') !== 0; + }); + + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_URL, $endpoint); - switch (strtoupper($method)) { - case 'POST': - curl_setopt($ch, CURLOPT_HTTPHEADER, $header); - if (!empty($params)) { - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); + // Prepare multipart data + $postData = []; + + // Add regular form fields + foreach ($params as $key => $value) { + if (is_array($value)) { + // Handle nested arrays (like colors, localized_address) + foreach ($value as $subKey => $subValue) { + $postData[$key . '[' . $subKey . ']'] = $subValue; } - curl_setopt($ch, CURLOPT_POST, true); - break; + } else { + $postData[$key] = $value; + } + } - case 'POST_MULTIPART': - $multipartHeaders = []; - foreach ($header as $h) { - if (stripos($h, 'Content-Type:') !== 0) { - $multipartHeaders[] = $h; - } + // Add files + foreach ($files as $fieldName => $filePath) { + if (file_exists($filePath)) { + if (class_exists('CURLFile')) { + // PHP 5.5+ + $postData[$fieldName] = new \CURLFile($filePath); + } else { + // PHP 5.4 compatibility + $postData[$fieldName] = '@' . $filePath; } - curl_setopt($ch, CURLOPT_HTTPHEADER, $multipartHeaders); + } + } - if (!empty($params)) { - $multipartData = $this->buildMultipartData($params); - curl_setopt($ch, CURLOPT_POSTFIELDS, $multipartData); + curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); + + $response = curl_exec($ch); + $info = curl_getinfo($ch); + curl_close($ch); + + return [ + 'response' => $response, + 'httpCode' => $info['http_code'] + ]; + } + + /** + * Extract file fields from params for multipart upload + * + * @param array $params Reference to params array + * @return array Files array for multipart upload + */ + private function extractFiles(array &$params) + { + $files = []; + + foreach ($params as $field => $value) { + if (is_string($value) && !empty($value)) { + // Check if it looks like a file path (not a URL and file exists) + if (!filter_var($value, FILTER_VALIDATE_URL) && file_exists($value)) { + $files[$field] = $value; + unset($params[$field]); // Remove from params as it will be sent as file } + } + } + + return $files; + } + + private function call($endpoint, array $params = [], $method, array $headers = []) + { + $ch = $this->init(); + + $header = array_merge($this->header, $headers); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + switch (strtoupper($method)) { + case 'POST': curl_setopt($ch, CURLOPT_POST, true); + if (!empty($params)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); + } break; - case 'PUT': case 'DELETE': - curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_HTTPGET, false); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); if (!empty($params)) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); } break; - case 'GET': - curl_setopt($ch, CURLOPT_HTTPHEADER, $header); if (!empty($params)) { $endpoint .= '?' . http_build_query($params); } @@ -116,33 +209,4 @@ private function call($endpoint, array $params = [], $method, array $headers = [ 'httpCode' => $info['http_code'] ]; } - - private function buildMultipartData(array $data, $prefix = '') - { - $result = []; - - foreach ($data as $key => $value) { - $fieldName = $prefix ? $prefix . '[' . $key . ']' : $key; - - if (is_array($value)) { - $nestedData = $this->buildMultipartData($value, $fieldName); - $result = array_merge($result, $nestedData); - } elseif (is_string($value) && substr($value, 0, 1) === '@') { - if (class_exists('CURLFile')) { - $filePath = substr($value, 1); - if (file_exists($filePath)) { - $result[$fieldName] = new CURLFile($filePath); - } else { - $result[$fieldName] = $value; - } - } else { - $result[$fieldName] = $value; - } - } else { - $result[$fieldName] = (string) $value; - } - } - - return $result; - } -} +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Template.php b/lib/FasterPay/Services/Business/EInvoice/Template.php index 4de2e8b..7672394 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Template.php +++ b/lib/FasterPay/Services/Business/EInvoice/Template.php @@ -13,39 +13,14 @@ class Template extends GeneralService /** * Create a new invoice template * - * @param array $params Template parameters + * @param array $params Template parameters (files auto-detected) * @return GeneralResponse * @throws Exception */ public function createTemplate(array $params = []) { - if (empty($params['name'])) { - throw new Exception('Template name is required'); - } - - if (empty($params['country_code'])) { - throw new Exception('Country code is required'); - } - - // Validate country code format - if (strlen($params['country_code']) !== 2) { - throw new Exception('Country code must be 2 characters (ISO 3166-1 alpha-2)'); - } - - // Validate colors if provided - if (!empty($params['colors'])) { - if (!empty($params['colors']['primary']) && !$this->isValidHexColor($params['colors']['primary'])) { - throw new Exception('Primary color must be a valid hex color'); - } - if (!empty($params['colors']['secondary']) && !$this->isValidHexColor($params['colors']['secondary'])) { - throw new Exception('Secondary color must be a valid hex color'); - } - } - $endpoint = $this->httpService->getEndPoint($this->endpoint); - $response = $this->httpService->getHttpClient()->post($endpoint, $params); - return new GeneralResponse($response); } @@ -73,7 +48,7 @@ public function getTemplate($templateId = '') * Update template * * @param string $templateId Template ID - * @param array $params Updated template parameters + * @param array $params Updated template parameters (files auto-detected) * @return GeneralResponse * @throws Exception */ @@ -83,20 +58,8 @@ public function updateTemplate($templateId = '', array $params = []) throw new Exception('Template ID is required'); } - // Validate colors if provided - if (!empty($params['colors'])) { - if (!empty($params['colors']['primary']) && !$this->isValidHexColor($params['colors']['primary'])) { - throw new Exception('Primary color must be a valid hex color'); - } - if (!empty($params['colors']['secondary']) && !$this->isValidHexColor($params['colors']['secondary'])) { - throw new Exception('Secondary color must be a valid hex color'); - } - } - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $templateId); - $response = $this->httpService->getHttpClient()->put($endpoint, $params); - return new GeneralResponse($response); } @@ -123,26 +86,13 @@ public function deleteTemplate($templateId = '') /** * List templates * - * @param array $filters Optional filters + * @param array $filters Optional filters (page, per_page, filter) * @return GeneralResponse */ public function listTemplates(array $filters = []) { $endpoint = $this->httpService->getEndPoint($this->endpoint); - $response = $this->httpService->getHttpClient()->get($endpoint, $filters); - return new GeneralResponse($response); } - - /** - * Validate hex color format - * - * @param string $color Hex color string - * @return bool - */ - private function isValidHexColor($color) - { - return preg_match('/^#[a-f0-9]{6}$/i', $color); - } } \ No newline at end of file From d3fdf612dab3f89d02d300bb37d1218e39a19e92 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 5 Aug 2025 19:34:27 +0700 Subject: [PATCH 04/20] update --- code-samples/business/e-invoice/product.php | 382 ++++++++++-------- .../Services/Business/EInvoice/Product.php | 87 +--- 2 files changed, 225 insertions(+), 244 deletions(-) diff --git a/code-samples/business/e-invoice/product.php b/code-samples/business/e-invoice/product.php index 6705b83..5360d42 100644 --- a/code-samples/business/e-invoice/product.php +++ b/code-samples/business/e-invoice/product.php @@ -11,14 +11,14 @@ echo "FasterPay E-Invoice Product API Examples\n"; echo "=========================================\n\n"; -// Example 1: Create a digital product -echo "1. Creating a digital product\n"; -echo "-----------------------------\n"; +// Example 1: Create a digital product with multiple currencies +echo "1. Creating a digital product with multiple currencies\n"; +echo "------------------------------------------------------\n"; $digitalProductData = [ + 'name' => 'Website Development Package', 'sku' => 'WEB-DEV-001', 'type' => 'digital', - 'name' => 'Website Development Package', 'description' => 'Complete website development with modern responsive design, SEO optimization, and content management system.', 'prices' => [ [ @@ -28,41 +28,46 @@ [ 'price' => 2100.00, 'currency' => 'EUR' + ], + [ + 'price' => 1850.00, + 'currency' => 'GBP' ] ] ]; try { - $productResponse = $businessGateway->eInvoiceProductService()->createProduct($digitalProductData); - - if ($productResponse->isSuccessful()) { - echo "✓ Digital product created successfully\n"; - $responseData = $productResponse->getDecodeResponse(); - $productId = $responseData['data']['id'] ?? 'PD-' . time(); - echo " Product ID: $productId\n"; - echo " SKU: {$digitalProductData['sku']}\n"; - echo " Name: {$digitalProductData['name']}\n"; - echo " Type: {$digitalProductData['type']}\n"; - echo " Prices: \$2,500 USD / €2,100 EUR\n"; - echo " Image URL: " . ($responseData['data']['image_url'] ?? 'No image uploaded') . "\n"; + $digitalProductResponse = $businessGateway->eInvoiceProductService()->createProduct($digitalProductData); + + if ($digitalProductResponse->isSuccessful()) { + echo "Digital product created successfully\n"; + $responseData = $digitalProductResponse->getDecodeResponse(); + $digitalProductId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-DIGITAL-' . time(); + echo " Product ID: " . $digitalProductId . "\n"; + echo " SKU: " . $digitalProductData['sku'] . "\n"; + echo " Name: " . $digitalProductData['name'] . "\n"; + echo " Type: " . $digitalProductData['type'] . "\n"; + echo " Prices: USD 2500.00 / EUR 2100.00 / GBP 1850.00\n"; + echo " Image URL: " . (isset($responseData['data']['image_url']) ? $responseData['data']['image_url'] : 'No image uploaded') . "\n"; } else { - echo "✗ Error: " . $productResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $digitalProductResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 2: Create a physical product -echo "2. Creating a physical product\n"; -echo "------------------------------\n"; +// Example 2: Create a physical product with image upload (multipart) +echo "2. Creating a physical product with image upload\n"; +echo "------------------------------------------------\n"; $physicalProductData = [ + 'name' => 'Professional Laptop 15 inch', 'sku' => 'LAPTOP-PRO-15', 'type' => 'physical', - 'name' => 'Professional Laptop 15"', 'description' => 'High-performance laptop with 16GB RAM, 512GB SSD, and professional graphics card. Perfect for developers and designers.', + 'image' => '/path/to/laptop-image.jpg', // This will trigger multipart upload 'prices' => [ [ 'price' => 1899.99, @@ -71,263 +76,288 @@ [ 'price' => 1649.99, 'currency' => 'EUR' - ], - [ - 'price' => 1499.99, - 'currency' => 'GBP' ] ] ]; try { - $laptopResponse = $businessGateway->eInvoiceProductService()->createProduct($physicalProductData); - - if ($laptopResponse->isSuccessful()) { - echo "✓ Physical product created successfully\n"; - $responseData = $laptopResponse->getDecodeResponse(); - $laptopId = $responseData['data']['id'] ?? 'PD-LAPTOP-' . time(); - echo " Product ID: $laptopId\n"; - echo " SKU: {$physicalProductData['sku']}\n"; - echo " Name: {$physicalProductData['name']}\n"; - echo " Type: {$physicalProductData['type']}\n"; - echo " Multi-currency pricing: USD/EUR/GBP\n"; + $physicalProductResponse = $businessGateway->eInvoiceProductService()->createProduct($physicalProductData); + + if ($physicalProductResponse->isSuccessful()) { + echo "Physical product created successfully\n"; + $responseData = $physicalProductResponse->getDecodeResponse(); + $physicalProductId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-PHYSICAL-' . time(); + echo " Product ID: " . $physicalProductId . "\n"; + echo " SKU: " . $physicalProductData['sku'] . "\n"; + echo " Name: " . $physicalProductData['name'] . "\n"; + echo " Type: " . $physicalProductData['type'] . "\n"; + echo " Prices: USD 1899.99 / EUR 1649.99\n"; + echo " Image URL: " . (isset($responseData['data']['image_url']) ? $responseData['data']['image_url'] : 'No image uploaded') . "\n"; } else { - echo "✗ Error: " . $laptopResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $physicalProductResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 3: Create a service product -echo "3. Creating a service product\n"; -echo "-----------------------------\n"; - -$serviceProductData = [ - 'sku' => 'CONSULT-HOUR', - 'type' => 'service', - 'name' => 'Technical Consulting Hour', - 'description' => 'One hour of expert technical consulting for software architecture, system design, and performance optimization.', - 'prices' => [ - [ - 'price' => 150.00, - 'currency' => 'USD' - ] - ] -]; - -try { - $consultingResponse = $businessGateway->eInvoiceProductService()->createProduct($serviceProductData); - - if ($consultingResponse->isSuccessful()) { - echo "✓ Service product created successfully\n"; - $responseData = $consultingResponse->getDecodeResponse(); - $consultingId = $responseData['data']['id'] ?? 'PD-CONSULT-' . time(); - echo " Product ID: $consultingId\n"; - echo " SKU: {$serviceProductData['sku']}\n"; - echo " Name: {$serviceProductData['name']}\n"; - echo " Type: {$serviceProductData['type']}\n"; - echo " Rate: \$150/hour\n"; - } else { - echo "✗ Error: " . $consultingResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 4: Get product details -echo "4. Getting product details\n"; +// Example 3: Get product details +echo "3. Getting product details\n"; echo "--------------------------\n"; -$productId = $productId ?? 'PD-' . time(); +$productIdToGet = isset($digitalProductId) ? $digitalProductId : 'PD-250528-L5CC'; try { - $detailsResponse = $businessGateway->eInvoiceProductService()->getProduct($productId); - - if ($detailsResponse->isSuccessful()) { - echo "✓ Product details retrieved\n"; - $details = $detailsResponse->getDecodeResponse(); - $product = $details['data'] ?? []; - - echo " ID: " . ($product['id'] ?? $productId) . "\n"; - echo " SKU: " . ($product['sku'] ?? 'N/A') . "\n"; - echo " Name: " . ($product['name'] ?? 'N/A') . "\n"; - echo " Type: " . ($product['type'] ?? 'N/A') . "\n"; - echo " Description: " . (substr($product['description'] ?? '', 0, 50) . '...') . "\n"; - - $prices = $product['prices'] ?? []; - if (!empty($prices)) { - echo " Prices: "; - foreach ($prices as $price) { - echo $price['currency'] . ' ' . $price['price'] . ' '; + $productDetailsResponse = $businessGateway->eInvoiceProductService()->getProduct($productIdToGet); + + if ($productDetailsResponse->isSuccessful()) { + echo "Product details retrieved successfully\n"; + $productData = $productDetailsResponse->getDecodeResponse(); + + if (isset($productData['data'])) { + $product = $productData['data']; + echo " Product ID: " . (isset($product['id']) ? $product['id'] : 'N/A') . "\n"; + echo " SKU: " . (isset($product['sku']) ? $product['sku'] : 'N/A') . "\n"; + echo " Name: " . (isset($product['name']) ? $product['name'] : 'N/A') . "\n"; + echo " Type: " . (isset($product['type']) ? $product['type'] : 'N/A') . "\n"; + echo " Description: " . (isset($product['description']) ? substr($product['description'], 0, 100) . '...' : 'N/A') . "\n"; + + if (isset($product['prices']) && is_array($product['prices'])) { + echo " Prices:\n"; + foreach ($product['prices'] as $price) { + $priceAmount = isset($price['price']) ? $price['price'] : '0.00'; + $currency = isset($price['currency']) ? $price['currency'] : 'N/A'; + echo " - " . $priceAmount . " " . $currency . "\n"; + } } - echo "\n"; } } else { - echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $productDetailsResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 5: Update product -echo "5. Updating product\n"; -echo "-------------------\n"; +// Example 4: Update product with image upload (multipart) +echo "4. Updating product with image upload\n"; +echo "-------------------------------------\n"; + +$productIdToUpdate = isset($physicalProductId) ? $physicalProductId : 'PD-UPDATE-' . time(); $updateData = [ - 'description' => 'Updated: Premium website development package with advanced SEO, e-commerce integration, and 6 months support.', + 'name' => 'Professional Laptop 15 inch - Updated Edition', + 'description' => 'Updated high-performance laptop with enhanced features: 32GB RAM, 1TB SSD, and latest graphics card.', + 'image' => '/path/to/updated-laptop-image.jpg', // This will trigger multipart upload 'prices' => [ [ - 'price' => 2750.00, + 'price' => 2199.99, 'currency' => 'USD' ], [ - 'price' => 2300.00, + 'price' => 1899.99, 'currency' => 'EUR' + ], + [ + 'price' => 1699.99, + 'currency' => 'GBP' ] ] ]; try { - $updateResponse = $businessGateway->eInvoiceProductService()->updateProduct($productId, $updateData); + $updateResponse = $businessGateway->eInvoiceProductService()->updateProduct($productIdToUpdate, $updateData); if ($updateResponse->isSuccessful()) { - echo "✓ Product updated successfully\n"; - echo " Updated pricing: \$2,750 USD / €2,300 EUR\n"; - echo " Updated description with enhanced features\n"; + echo "Product updated successfully\n"; + $responseData = $updateResponse->getDecodeResponse(); + echo " Product ID: " . $productIdToUpdate . "\n"; + echo " Updated Name: " . $updateData['name'] . "\n"; + echo " Updated Prices: USD 2199.99 / EUR 1899.99 / GBP 1699.99\n"; + echo " Image URL: " . (isset($responseData['data']['image_url']) ? $responseData['data']['image_url'] : 'No image uploaded') . "\n"; } else { - echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 6: List all products -echo "6. Listing all products\n"; -echo "-----------------------\n"; +// Example 5: List products with filters +echo "5. Listing products with filters\n"; +echo "--------------------------------\n"; + +$filters = [ + 'limit' => 20, + 'offset' => 0, + 'type' => 'digital' +]; try { - $listResponse = $businessGateway->eInvoiceProductService()->listProducts(); + $listResponse = $businessGateway->eInvoiceProductService()->listProducts($filters); if ($listResponse->isSuccessful()) { - echo "✓ Product list retrieved\n"; + echo "Product list retrieved successfully\n"; $listData = $listResponse->getDecodeResponse(); - $products = $listData['data']['data'] ?? []; - - echo " Total products: " . count($products) . "\n"; - - if (!empty($products)) { - echo " Product catalog:\n"; + + if (isset($listData['data']) && is_array($listData['data'])) { + echo " Found " . count($listData['data']) . " digital products\n"; + + // Display first few products + $products = array_slice($listData['data'], 0, 3); foreach ($products as $product) { - $id = $product['id'] ?? 'Unknown'; - $sku = $product['sku'] ?? 'N/A'; - $name = $product['name'] ?? 'Unnamed'; - $type = $product['type'] ?? 'N/A'; - - echo " - $name (SKU: $sku, Type: $type, ID: $id)\n"; + $id = isset($product['id']) ? $product['id'] : 'Unknown'; + $name = isset($product['name']) ? $product['name'] : 'Unnamed'; + $sku = isset($product['sku']) ? $product['sku'] : 'No SKU'; + $type = isset($product['type']) ? $product['type'] : 'Unknown'; + + echo " - " . $name . " (" . $id . ", SKU: " . $sku . ", Type: " . $type . ")\n"; + } + + if (count($listData['data']) > 3) { + echo " ... and " . (count($listData['data']) - 3) . " more\n"; } } } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 7: Search product by SKU -echo "7. Searching product by SKU\n"; -echo "----------------------------\n"; +// Example 6: Delete product price +echo "6. Deleting product price\n"; +echo "-------------------------\n"; -try { - $skuResponse = $businessGateway->eInvoiceProductService()->getProductBySku('WEB-DEV-001'); +$productIdForPriceDeletion = isset($digitalProductId) ? $digitalProductId : 'PD-PRICE-DELETE-' . time(); +$currencyToDelete = 'GBP'; - if ($skuResponse->isSuccessful()) { - echo "✓ Product found by SKU\n"; - $skuData = $skuResponse->getDecodeResponse(); - $products = $skuData['data']['data'] ?? []; +try { + $deletePriceResponse = $businessGateway->eInvoiceProductService()->deleteProductPrice($productIdForPriceDeletion, $currencyToDelete); - if (!empty($products)) { - $product = $products[0]; - echo " Found: " . ($product['name'] ?? 'Unknown') . "\n"; - echo " Type: " . ($product['type'] ?? 'N/A') . "\n"; - } + if ($deletePriceResponse->isSuccessful()) { + echo "Product price deleted successfully\n"; + echo " Product ID: " . $productIdForPriceDeletion . "\n"; + echo " Deleted Currency: " . $currencyToDelete . "\n"; } else { - echo "✗ Error: " . $skuResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $deletePriceResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 8: Create a product bundle -echo "8. Creating product bundles\n"; -echo "---------------------------\n"; +// Example 7: Create service products +echo "7. Creating service products\n"; +echo "----------------------------\n"; -$bundleProducts = [ +$serviceProducts = [ [ - 'sku' => 'STARTUP-BUNDLE', + 'name' => 'Monthly Consultation Services', + 'sku' => 'CONSULT-MONTHLY', 'type' => 'digital', - 'name' => 'Startup Launch Bundle', - 'description' => 'Everything you need to launch your startup: website, logo design, business cards, and marketing materials.', + 'description' => 'Professional monthly consultation services including strategy planning and business analysis.', 'prices' => [ [ - 'price' => 3999.00, + 'price' => 500.00, 'currency' => 'USD' ] ] ], [ - 'sku' => 'ENTERPRISE-PACKAGE', - 'type' => 'service', - 'name' => 'Enterprise Solution Package', - 'description' => 'Complete enterprise solution with custom development, integration, training, and 1-year support.', + 'name' => 'Premium Support Package', + 'sku' => 'SUPPORT-PREMIUM', + 'type' => 'digital', + 'description' => '24/7 premium support with dedicated account manager and priority response.', 'prices' => [ [ - 'price' => 25000.00, + 'price' => 299.99, 'currency' => 'USD' + ], + [ + 'price' => 249.99, + 'currency' => 'EUR' ] ] ] ]; -echo "Creating product bundles:\n"; - -foreach ($bundleProducts as $bundleData) { +foreach ($serviceProducts as $serviceData) { try { - $response = $businessGateway->eInvoiceProductService()->createProduct($bundleData); + $serviceResponse = $businessGateway->eInvoiceProductService()->createProduct($serviceData); - if ($response->isSuccessful()) { - $responseData = $response->getDecodeResponse(); - $bundleId = $responseData['data']['id'] ?? 'PD-BUNDLE-' . time(); - $price = $bundleData['prices'][0]['price']; - $currency = $bundleData['prices'][0]['currency']; + if ($serviceResponse->isSuccessful()) { + $responseData = $serviceResponse->getDecodeResponse(); + $serviceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-SERVICE-' . time(); + $price = $serviceData['prices'][0]['price']; + $currency = $serviceData['prices'][0]['currency']; - echo " ✓ {$bundleData['name']}: $" . number_format($price, 2) . " $currency (ID: $bundleId)\n"; + echo " Service product created: " . $serviceData['name'] . " (ID: " . $serviceId . ", Price: " . $price . " " . $currency . ")\n"; } else { - echo " ✗ Failed to create {$bundleData['name']}\n"; + echo " Error creating " . $serviceData['name'] . ": " . $serviceResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo " ✗ Exception creating {$bundleData['name']}: " . $e->getMessage() . "\n"; + echo " Exception creating " . $serviceData['name'] . ": " . $e->getMessage() . "\n"; } } +echo "\n"; + +// Example 8: Delete product +echo "8. Deleting product\n"; +echo "-------------------\n"; + +$productToDelete = 'PD-DELETE-' . time(); + +try { + $deleteResponse = $businessGateway->eInvoiceProductService()->deleteProduct($productToDelete); + + if ($deleteResponse->isSuccessful()) { + echo "Product deleted successfully\n"; + echo " Deleted Product ID: " . $productToDelete . "\n"; + } else { + echo "Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + echo "\nE-Invoice Product API examples completed!\n"; echo "Use cases:\n"; echo "• Product catalog management\n"; echo "• Multi-currency pricing\n"; -echo "• Service offering management\n"; echo "• Digital product distribution\n"; echo "• Physical inventory integration\n"; -echo "• Bundle and package creation\n"; +echo "• Service offering management\n"; echo "• SKU-based product lookup\n"; -echo "• Dynamic pricing updates\n"; \ No newline at end of file +echo "• Image upload and management\n"; +echo "• Price management by currency\n"; +echo "• Product type categorization\n"; +echo "• Bulk product operations\n"; + +echo "\nMultipart Support:\n"; +echo "• Automatic file detection in HttpClient\n"; +echo "• Image uploads supported for create and update\n"; +echo "• Uses multipart/form-data when image files present\n"; +echo "• POST method for create with automatic multipart\n"; +echo "• PUT method for update (converts to POST + _method=PUT for multipart)\n"; +echo "• Maximum image size: 1MB\n"; +echo "• Supported formats: JPG, PNG, GIF\n"; + +echo "\nProduct Types:\n"; +echo "• digital: Software, licenses, digital downloads\n"; +echo "• physical: Hardware, merchandise, shipped items\n"; + +echo "\nValidation Notes:\n"; +echo "• Only ID field validation implemented (as requested)\n"; +echo "• API handles all parameter validation server-side\n"; +echo "• Currency codes must be ISO-4217 format (3 characters)\n"; +echo "• Price amounts must be numeric and non-negative\n"; +echo "• Product names limited to 191 characters\n"; +echo "• SKU limited to 50 characters\n"; \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Product.php b/lib/FasterPay/Services/Business/EInvoice/Product.php index a11d1a2..aba162e 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Product.php +++ b/lib/FasterPay/Services/Business/EInvoice/Product.php @@ -11,49 +11,17 @@ class Product extends GeneralService protected $endpoint = 'api/external/invoices/products'; /** - * Create a new invoice product + * Create a new product + * Supports multipart/form-data for image uploads * * @param array $params Product parameters * @return GeneralResponse - * @throws Exception */ public function createProduct(array $params = []) { - if (empty($params['name'])) { - throw new Exception('Product name is required'); - } - - if (empty($params['sku'])) { - throw new Exception('Product SKU is required'); - } - - if (empty($params['type'])) { - throw new Exception('Product type is required'); - } - - // Validate product type - $validTypes = ['digital', 'physical', 'service']; - if (!in_array($params['type'], $validTypes)) { - throw new Exception('Product type must be one of: ' . implode(', ', $validTypes)); - } - - // Validate prices if provided - if (!empty($params['prices']) && is_array($params['prices'])) { - foreach ($params['prices'] as $price) { - if (!isset($price['price']) || !is_numeric($price['price'])) { - throw new Exception('Each price must have a numeric price value'); - } - if (empty($price['currency']) || strlen($price['currency']) !== 3) { - throw new Exception('Each price must have a valid 3-character currency code'); - } - if ($price['price'] < 0) { - throw new Exception('Price must be non-negative'); - } - } - } - $endpoint = $this->httpService->getEndPoint($this->endpoint); + // Use POST method - HttpClient will auto-detect files and use multipart if needed $response = $this->httpService->getHttpClient()->post($endpoint, $params); return new GeneralResponse($response); @@ -81,6 +49,7 @@ public function getProduct($productId = '') /** * Update product + * Supports multipart/form-data for image uploads * * @param string $productId Product ID * @param array $params Updated product parameters @@ -93,31 +62,9 @@ public function updateProduct($productId = '', array $params = []) throw new Exception('Product ID is required'); } - // Validate product type if provided - if (!empty($params['type'])) { - $validTypes = ['digital', 'physical', 'service']; - if (!in_array($params['type'], $validTypes)) { - throw new Exception('Product type must be one of: ' . implode(', ', $validTypes)); - } - } - - // Validate prices if provided - if (!empty($params['prices']) && is_array($params['prices'])) { - foreach ($params['prices'] as $price) { - if (!isset($price['price']) || !is_numeric($price['price'])) { - throw new Exception('Each price must have a numeric price value'); - } - if (empty($price['currency']) || strlen($price['currency']) !== 3) { - throw new Exception('Each price must have a valid 3-character currency code'); - } - if ($price['price'] < 0) { - throw new Exception('Price must be non-negative'); - } - } - } - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $productId); + // Use PUT method - HttpClient will auto-detect files and use POST + _method=PUT if needed $response = $this->httpService->getHttpClient()->put($endpoint, $params); return new GeneralResponse($response); @@ -144,9 +91,9 @@ public function deleteProduct($productId = '') } /** - * List products + * List products with optional filters * - * @param array $filters Optional filters + * @param array $filters Optional filters (limit, offset, sku, type, etc.) * @return GeneralResponse */ public function listProducts(array $filters = []) @@ -159,22 +106,26 @@ public function listProducts(array $filters = []) } /** - * Search products by SKU + * Delete product price by currency * - * @param string $sku Product SKU + * @param string $productId Product ID + * @param string $currency Currency code (ISO-4217 format) * @return GeneralResponse * @throws Exception */ - public function getProductBySku($sku = '') + public function deleteProductPrice($productId = '', $currency = '') { - if (empty($sku)) { - throw new Exception('Product SKU is required'); + if (empty($productId)) { + throw new Exception('Product ID is required'); } - $endpoint = $this->httpService->getEndPoint($this->endpoint); - $params = ['sku' => $sku]; + if (empty($currency)) { + throw new Exception('Currency is required'); + } - $response = $this->httpService->getHttpClient()->get($endpoint, $params); + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $productId . '/prices/' . $currency); + + $response = $this->httpService->getHttpClient()->delete($endpoint); return new GeneralResponse($response); } From b1be0e2f31e5933f05852fcf615d4cb5bdf6680d Mon Sep 17 00:00:00 2001 From: James Date: Tue, 5 Aug 2025 20:07:01 +0700 Subject: [PATCH 05/20] update --- code-samples/business/e-invoice/discount.php | 323 +++++++-------- code-samples/business/e-invoice/tax.php | 367 +++++++++++------- .../Services/Business/EInvoice/Discount.php | 64 +-- .../Services/Business/EInvoice/Tax.php | 53 --- 4 files changed, 414 insertions(+), 393 deletions(-) diff --git a/code-samples/business/e-invoice/discount.php b/code-samples/business/e-invoice/discount.php index a652a83..45e207a 100644 --- a/code-samples/business/e-invoice/discount.php +++ b/code-samples/business/e-invoice/discount.php @@ -18,7 +18,7 @@ $flatDiscountData = [ 'name' => 'Early Bird Discount', 'type' => 'flat', - 'value' => 0.1, + 'value' => 10.00, 'currency' => 'USD', 'description' => '$10 discount for early payment' ]; @@ -29,12 +29,12 @@ if ($discountResponse->isSuccessful()) { echo "✓ Flat discount created successfully\n"; $responseData = $discountResponse->getDecodeResponse(); - $discountId = $responseData['data']['id'] ?? 'DC-' . time(); - echo " Discount ID: $discountId\n"; - echo " Name: {$flatDiscountData['name']}\n"; - echo " Type: {$flatDiscountData['type']}\n"; - echo " Value: $" . $flatDiscountData['value'] . " {$flatDiscountData['currency']}\n"; - echo " Description: {$flatDiscountData['description']}\n"; + $discountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-' . time(); + echo " Discount ID: " . $discountId . "\n"; + echo " Name: " . $flatDiscountData['name'] . "\n"; + echo " Type: " . $flatDiscountData['type'] . "\n"; + echo " Value: $" . number_format($flatDiscountData['value'], 2) . " " . $flatDiscountData['currency'] . "\n"; + echo " Description: " . $flatDiscountData['description'] . "\n"; } else { echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; } @@ -61,12 +61,12 @@ if ($volumeResponse->isSuccessful()) { echo "✓ Percentage discount created successfully\n"; $responseData = $volumeResponse->getDecodeResponse(); - $volumeDiscountId = $responseData['data']['id'] ?? 'DC-VOLUME-' . time(); - echo " Discount ID: $volumeDiscountId\n"; - echo " Name: {$percentageDiscountData['name']}\n"; - echo " Type: {$percentageDiscountData['type']}\n"; - echo " Value: {$percentageDiscountData['value']}%\n"; - echo " Description: {$percentageDiscountData['description']}\n"; + $volumeDiscountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-VOLUME-' . time(); + echo " Discount ID: " . $volumeDiscountId . "\n"; + echo " Name: " . $percentageDiscountData['name'] . "\n"; + echo " Type: " . $percentageDiscountData['type'] . "\n"; + echo " Value: " . $percentageDiscountData['value'] . "%\n"; + echo " Description: " . $percentageDiscountData['description'] . "\n"; } else { echo "✗ Error: " . $volumeResponse->getErrors()->getMessage() . "\n"; } @@ -81,10 +81,10 @@ echo "----------------------------\n"; $loyaltyDiscountData = [ - 'name' => 'Loyal Customer Discount', + 'name' => 'Loyalty Customer Discount', 'type' => 'percentage', - 'value' => 10, - 'description' => '10% discount for returning customers' + 'value' => 25, + 'description' => '25% discount for loyal customers' ]; try { @@ -93,9 +93,12 @@ if ($loyaltyResponse->isSuccessful()) { echo "✓ Loyalty discount created successfully\n"; $responseData = $loyaltyResponse->getDecodeResponse(); - $loyaltyDiscountId = $responseData['data']['id'] ?? 'DC-LOYALTY-' . time(); - echo " Discount ID: $loyaltyDiscountId\n"; - echo " Value: {$loyaltyDiscountData['value']}% for loyal customers\n"; + $loyaltyDiscountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-LOYALTY-' . time(); + echo " Discount ID: " . $loyaltyDiscountId . "\n"; + echo " Name: " . $loyaltyDiscountData['name'] . "\n"; + echo " Type: " . $loyaltyDiscountData['type'] . "\n"; + echo " Value: " . $loyaltyDiscountData['value'] . "%\n"; + echo " Description: " . $loyaltyDiscountData['description'] . "\n"; } else { echo "✗ Error: " . $loyaltyResponse->getErrors()->getMessage() . "\n"; } @@ -106,27 +109,30 @@ echo "\n"; // Example 4: Get discount details -echo "4. Getting discount details\n"; -echo "---------------------------\n"; +echo "4. Retrieving discount details\n"; +echo "------------------------------\n"; -$discountId = $discountId ?? 'DC-' . time(); +$testDiscountId = isset($discountId) ? $discountId : 'DC-250527-WZX0'; try { - $detailsResponse = $businessGateway->eInvoiceDiscountService()->getDiscount($discountId); - - if ($detailsResponse->isSuccessful()) { - echo "✓ Discount details retrieved\n"; - $details = $detailsResponse->getDecodeResponse(); - $discount = $details['data'] ?? []; - - echo " ID: " . ($discount['id'] ?? $discountId) . "\n"; - echo " Name: " . ($discount['name'] ?? 'N/A') . "\n"; - echo " Type: " . ($discount['type'] ?? 'N/A') . "\n"; - echo " Value: " . ($discount['value'] ?? 'N/A') . "\n"; - echo " Currency: " . ($discount['currency'] ?? 'N/A') . "\n"; - echo " Description: " . ($discount['description'] ?? 'N/A') . "\n"; + $getDiscountResponse = $businessGateway->eInvoiceDiscountService()->getDiscount($testDiscountId); + + if ($getDiscountResponse->isSuccessful()) { + echo "✓ Discount details retrieved successfully\n"; + $discountData = $getDiscountResponse->getDecodeResponse(); + if (isset($discountData['data'])) { + $discount = $discountData['data']; + echo " Discount ID: " . (isset($discount['id']) ? $discount['id'] : $testDiscountId) . "\n"; + echo " Name: " . (isset($discount['name']) ? $discount['name'] : 'N/A') . "\n"; + echo " Type: " . (isset($discount['type']) ? $discount['type'] : 'N/A') . "\n"; + echo " Value: " . (isset($discount['value']) ? $discount['value'] : 'N/A') . "\n"; + if (isset($discount['currency'])) { + echo " Currency: " . $discount['currency'] . "\n"; + } + echo " Description: " . (isset($discount['description']) ? $discount['description'] : 'N/A') . "\n"; + } } else { - echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $getDiscountResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -138,18 +144,21 @@ echo "5. Updating discount\n"; echo "--------------------\n"; -$updateData = [ - 'value' => 0.15, - 'description' => 'Updated to $15 early payment discount' +$updateDiscountData = [ + 'name' => 'Updated Early Bird Discount', + 'description' => 'Updated early payment discount with better terms', + 'value' => 15.00 ]; try { - $updateResponse = $businessGateway->eInvoiceDiscountService()->updateDiscount($discountId, $updateData); + $updateResponse = $businessGateway->eInvoiceDiscountService()->updateDiscount($testDiscountId, $updateDiscountData); if ($updateResponse->isSuccessful()) { echo "✓ Discount updated successfully\n"; - echo " New value: $" . $updateData['value'] . "\n"; - echo " Updated description: {$updateData['description']}\n"; + echo " Discount ID: " . $testDiscountId . "\n"; + echo " Updated Name: " . $updateDiscountData['name'] . "\n"; + echo " Updated Value: $" . number_format($updateDiscountData['value'], 2) . "\n"; + echo " Updated Description: " . $updateDiscountData['description'] . "\n"; } else { echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } @@ -159,34 +168,30 @@ echo "\n"; -// Example 6: List all discounts -echo "6. Listing all discounts\n"; -echo "------------------------\n"; +// Example 6: List discounts +echo "6. Listing discounts\n"; +echo "--------------------\n"; + +$filters = [ + 'limit' => 10, + 'offset' => 0 +]; try { - $listResponse = $businessGateway->eInvoiceDiscountService()->listDiscounts(); + $listResponse = $businessGateway->eInvoiceDiscountService()->listDiscounts($filters); if ($listResponse->isSuccessful()) { - echo "✓ Discount list retrieved\n"; + echo "✓ Discount list retrieved successfully\n"; $listData = $listResponse->getDecodeResponse(); - $discounts = $listData['data']['data'] ?? []; - - echo " Total discounts: " . count($discounts) . "\n"; - - if (!empty($discounts)) { - echo " Available discounts:\n"; - foreach ($discounts as $discount) { - $id = $discount['id'] ?? 'Unknown'; - $name = $discount['name'] ?? 'Unnamed'; - $type = $discount['type'] ?? 'N/A'; - $value = $discount['value'] ?? 0; - $currency = $discount['currency'] ?? ''; - - if ($type === 'percentage') { - echo " - $name ($id): $value% off\n"; - } else { - echo " - $name ($id): $" . $value . " $currency off\n"; - } + if (isset($listData['data']) && is_array($listData['data'])) { + echo " Found " . count($listData['data']) . " discounts:\n"; + foreach ($listData['data'] as $discount) { + $id = isset($discount['id']) ? $discount['id'] : 'Unknown'; + $name = isset($discount['name']) ? $discount['name'] : 'Unnamed'; + $type = isset($discount['type']) ? $discount['type'] : 'Unknown'; + $value = isset($discount['value']) ? $discount['value'] : '0'; + $currency = isset($discount['currency']) ? ' ' . $discount['currency'] : ''; + echo " - " . $name . " (" . $id . ") - " . $type . ": " . $value . $currency . "\n"; } } } else { @@ -198,116 +203,128 @@ echo "\n"; -// Example 7: Create seasonal discounts -echo "7. Creating seasonal discounts\n"; +// Example 7: Delete discount +echo "7. Deleting discount\n"; +echo "--------------------\n"; + +$deleteTestDiscountId = isset($loyaltyDiscountId) ? $loyaltyDiscountId : 'DC-DELETE-' . time(); + +try { + $deleteResponse = $businessGateway->eInvoiceDiscountService()->deleteDiscount($deleteTestDiscountId); + + if ($deleteResponse->isSuccessful()) { + echo "✓ Discount deleted successfully\n"; + echo " Deleted Discount ID: " . $deleteTestDiscountId . "\n"; + } else { + echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 8: Using discounts in invoices (embedded discount object) +echo "8. Using discounts in invoices\n"; echo "------------------------------\n"; -$seasonalDiscounts = [ - [ - 'name' => 'Black Friday Special', - 'type' => 'percentage', - 'value' => 25, - 'description' => '25% off everything - Black Friday special' - ], - [ - 'name' => 'New Year Discount', - 'type' => 'flat', - 'value' => 50, - 'currency' => 'USD', - 'description' => '$50 off to start the new year right' - ], - [ - 'name' => 'Summer Sale', +$invoiceWithDiscountData = [ + 'currency' => 'USD', + 'summary' => 'Invoice with embedded discount', + 'number' => 'INV-DISC-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => 'CT-250527-AZARCIJE', + 'discount' => [ + 'name' => 'Seasonal Discount', 'type' => 'percentage', 'value' => 20, - 'description' => '20% summer discount on all services' + 'description' => '20% seasonal discount' + ], + 'items' => [ + [ + 'price' => 200.00, + 'quantity' => 1, + 'name' => 'Premium Service Package', + 'description' => 'Comprehensive service package' + ] ] ]; -$createdSeasonalDiscounts = []; - -foreach ($seasonalDiscounts as $discountData) { - try { - $response = $businessGateway->eInvoiceDiscountService()->createDiscount($discountData); - - if ($response->isSuccessful()) { - $responseData = $response->getDecodeResponse(); - $discountId = $responseData['data']['id'] ?? 'DC-SEASONAL-' . time(); - $createdSeasonalDiscounts[] = $discountId; - - if ($discountData['type'] === 'percentage') { - echo "✓ {$discountData['name']}: {$discountData['value']}% off (ID: $discountId)\n"; - } else { - echo "✓ {$discountData['name']}: $" . $discountData['value'] . " off (ID: $discountId)\n"; - } - } else { - echo "✗ Failed to create {$discountData['name']}: " . $response->getErrors()->getMessage() . "\n"; - } - } catch (FasterPay\Exception $e) { - echo "✗ Exception creating {$discountData['name']}: " . $e->getMessage() . "\n"; +try { + $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceWithDiscountData); + + if ($invoiceResponse->isSuccessful()) { + echo "✓ Invoice with embedded discount created successfully\n"; + $responseData = $invoiceResponse->getDecodeResponse(); + $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Invoice Number: " . $invoiceWithDiscountData['number'] . "\n"; + echo " Discount: " . $invoiceWithDiscountData['discount']['name'] . " (" . $invoiceWithDiscountData['discount']['value'] . "%)\n"; + } else { + echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; } -echo " Created " . count($createdSeasonalDiscounts) . " seasonal discount offers\n"; - echo "\n"; -// Example 8: Create tiered discounts for different customer levels -echo "8. Creating tiered customer discounts\n"; -echo "-------------------------------------\n"; +// Example 9: Create invoice with both tax and discount +echo "9. Creating invoice with tax and discount\n"; +echo "-----------------------------------------\n"; -$tieredDiscounts = [ - [ - 'name' => 'Bronze Member', - 'type' => 'percentage', - 'value' => 5, - 'description' => '5% discount for Bronze tier customers' - ], - [ - 'name' => 'Silver Member', +$combinedInvoiceData = [ + 'currency' => 'USD', + 'summary' => 'Invoice with tax and discount', + 'number' => 'INV-COMBO-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => 'CT-250527-AZARCIJE', + 'tax' => [ + 'name' => 'Sales Tax', 'type' => 'percentage', - 'value' => 10, - 'description' => '10% discount for Silver tier customers' + 'value' => 8.5, + 'description' => '8.5% sales tax' ], - [ - 'name' => 'Gold Member', - 'type' => 'percentage', - 'value' => 15, - 'description' => '15% discount for Gold tier customers' + 'discount' => [ + 'name' => 'First Time Customer', + 'type' => 'flat', + 'value' => 25.00, + 'currency' => 'USD', + 'description' => '$25 discount for first-time customers' ], - [ - 'name' => 'Platinum Member', - 'type' => 'percentage', - 'value' => 20, - 'description' => '20% discount for Platinum tier customers' + 'items' => [ + [ + 'price' => 500.00, + 'quantity' => 1, + 'name' => 'Professional Services', + 'description' => 'Complete professional service package' + ] ] ]; -echo "Creating customer tier discounts:\n"; - -foreach ($tieredDiscounts as $tierData) { - try { - $response = $businessGateway->eInvoiceDiscountService()->createDiscount($tierData); - - if ($response->isSuccessful()) { - $responseData = $response->getDecodeResponse(); - $tierId = $responseData['data']['id'] ?? 'DC-TIER-' . time(); - echo " ✓ {$tierData['name']}: {$tierData['value']}% (ID: $tierId)\n"; - } else { - echo " ✗ Failed to create {$tierData['name']}\n"; - } - } catch (FasterPay\Exception $e) { - echo " ✗ Exception creating {$tierData['name']}: " . $e->getMessage() . "\n"; +try { + $comboResponse = $businessGateway->eInvoiceService()->createInvoice($combinedInvoiceData); + + if ($comboResponse->isSuccessful()) { + echo "✓ Invoice with tax and discount created successfully\n"; + $responseData = $comboResponse->getDecodeResponse(); + $comboInvoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); + echo " Invoice ID: " . $comboInvoiceId . "\n"; + echo " Invoice Number: " . $combinedInvoiceData['number'] . "\n"; + echo " Tax: " . $combinedInvoiceData['tax']['name'] . " (" . $combinedInvoiceData['tax']['value'] . "%)\n"; + echo " Discount: " . $combinedInvoiceData['discount']['name'] . " ($" . $combinedInvoiceData['discount']['value'] . ")\n"; + } else { + echo "✗ Error: " . $comboResponse->getErrors()->getMessage() . "\n"; } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; } echo "\nE-Invoice Discount API examples completed!\n"; echo "Use cases:\n"; -echo "• Customer loyalty programs\n"; -echo "• Seasonal and promotional campaigns\n"; -echo "• Volume-based pricing strategies\n"; echo "• Early payment incentives\n"; -echo "• Tiered customer benefits\n"; -echo "• Dynamic pricing adjustments\n"; -echo "• Bulk order discounts\n"; -echo "• Customer retention strategies\n"; \ No newline at end of file +echo "• Volume purchase discounts\n"; +echo "• Loyalty customer rewards\n"; +echo "• Seasonal promotional offers\n"; +echo "• First-time customer discounts\n"; +echo "• Bulk order price reductions\n"; +echo "• Partner and affiliate discounts\n"; +echo "• Promotional campaign management\n"; \ No newline at end of file diff --git a/code-samples/business/e-invoice/tax.php b/code-samples/business/e-invoice/tax.php index ff31321..1155682 100644 --- a/code-samples/business/e-invoice/tax.php +++ b/code-samples/business/e-invoice/tax.php @@ -9,17 +9,17 @@ ]); echo "FasterPay E-Invoice Tax API Examples\n"; -echo "=====================================\n\n"; +echo "====================================\n\n"; // Example 1: Create a flat tax echo "1. Creating a flat tax\n"; echo "----------------------\n"; $flatTaxData = [ - 'name' => 'Sales Tax', + 'name' => 'Processing Fee', 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% flat sales tax rate' + 'value' => 2.50, + 'description' => 'Fixed processing fee per transaction' ]; try { @@ -28,12 +28,12 @@ if ($taxResponse->isSuccessful()) { echo "✓ Flat tax created successfully\n"; $responseData = $taxResponse->getDecodeResponse(); - $taxId = $responseData['data']['id'] ?? 'TX-' . time(); - echo " Tax ID: $taxId\n"; - echo " Name: {$flatTaxData['name']}\n"; - echo " Type: {$flatTaxData['type']}\n"; - echo " Rate: " . ($flatTaxData['value'] * 100) . "%\n"; - echo " Description: {$flatTaxData['description']}\n"; + $taxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-' . time(); + echo " Tax ID: " . $taxId . "\n"; + echo " Name: " . $flatTaxData['name'] . "\n"; + echo " Type: " . $flatTaxData['type'] . "\n"; + echo " Value: $" . number_format($flatTaxData['value'], 2) . "\n"; + echo " Description: " . $flatTaxData['description'] . "\n"; } else { echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; } @@ -48,26 +48,26 @@ echo "----------------------------\n"; $percentageTaxData = [ - 'name' => 'VAT', + 'name' => 'Sales Tax', 'type' => 'percentage', - 'value' => 20, - 'description' => '20% Value Added Tax (UK)' + 'value' => 8.25, + 'description' => '8.25% state sales tax' ]; try { - $vatResponse = $businessGateway->eInvoiceTaxService()->createTax($percentageTaxData); + $salesTaxResponse = $businessGateway->eInvoiceTaxService()->createTax($percentageTaxData); - if ($vatResponse->isSuccessful()) { + if ($salesTaxResponse->isSuccessful()) { echo "✓ Percentage tax created successfully\n"; - $responseData = $vatResponse->getDecodeResponse(); - $vatId = $responseData['data']['id'] ?? 'TX-VAT-' . time(); - echo " Tax ID: $vatId\n"; - echo " Name: {$percentageTaxData['name']}\n"; - echo " Type: {$percentageTaxData['type']}\n"; - echo " Rate: {$percentageTaxData['value']}%\n"; - echo " Description: {$percentageTaxData['description']}\n"; + $responseData = $salesTaxResponse->getDecodeResponse(); + $salesTaxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-SALES-' . time(); + echo " Tax ID: " . $salesTaxId . "\n"; + echo " Name: " . $percentageTaxData['name'] . "\n"; + echo " Type: " . $percentageTaxData['type'] . "\n"; + echo " Value: " . $percentageTaxData['value'] . "%\n"; + echo " Description: " . $percentageTaxData['description'] . "\n"; } else { - echo "✗ Error: " . $vatResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $salesTaxResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -75,28 +75,31 @@ echo "\n"; -// Example 3: Create GST tax -echo "3. Creating GST tax\n"; +// Example 3: Create VAT tax +echo "3. Creating VAT tax\n"; echo "-------------------\n"; -$gstTaxData = [ - 'name' => 'GST', - 'type' => 'flat', - 'value' => 0.10, - 'description' => '10% Goods and Services Tax' +$vatTaxData = [ + 'name' => 'VAT', + 'type' => 'percentage', + 'value' => 20, + 'description' => '20% Value Added Tax' ]; try { - $gstResponse = $businessGateway->eInvoiceTaxService()->createTax($gstTaxData); - - if ($gstResponse->isSuccessful()) { - echo "✓ GST tax created successfully\n"; - $responseData = $gstResponse->getDecodeResponse(); - $gstId = $responseData['data']['id'] ?? 'TX-GST-' . time(); - echo " Tax ID: $gstId\n"; - echo " Rate: " . ($gstTaxData['value'] * 100) . "% GST\n"; + $vatResponse = $businessGateway->eInvoiceTaxService()->createTax($vatTaxData); + + if ($vatResponse->isSuccessful()) { + echo "✓ VAT tax created successfully\n"; + $responseData = $vatResponse->getDecodeResponse(); + $vatTaxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-VAT-' . time(); + echo " Tax ID: " . $vatTaxId . "\n"; + echo " Name: " . $vatTaxData['name'] . "\n"; + echo " Type: " . $vatTaxData['type'] . "\n"; + echo " Value: " . $vatTaxData['value'] . "%\n"; + echo " Description: " . $vatTaxData['description'] . "\n"; } else { - echo "✗ Error: " . $gstResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $vatResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -105,26 +108,27 @@ echo "\n"; // Example 4: Get tax details -echo "4. Getting tax details\n"; -echo "----------------------\n"; +echo "4. Retrieving tax details\n"; +echo "-------------------------\n"; -$taxId = $taxId ?? 'TX-' . time(); +$testTaxId = isset($taxId) ? $taxId : 'TX-250527-2E9N'; try { - $detailsResponse = $businessGateway->eInvoiceTaxService()->getTax($taxId); - - if ($detailsResponse->isSuccessful()) { - echo "✓ Tax details retrieved\n"; - $details = $detailsResponse->getDecodeResponse(); - $tax = $details['data'] ?? []; - - echo " ID: " . ($tax['id'] ?? $taxId) . "\n"; - echo " Name: " . ($tax['name'] ?? 'N/A') . "\n"; - echo " Type: " . ($tax['type'] ?? 'N/A') . "\n"; - echo " Value: " . ($tax['value'] ?? 'N/A') . "\n"; - echo " Description: " . ($tax['description'] ?? 'N/A') . "\n"; + $getTaxResponse = $businessGateway->eInvoiceTaxService()->getTax($testTaxId); + + if ($getTaxResponse->isSuccessful()) { + echo "✓ Tax details retrieved successfully\n"; + $taxData = $getTaxResponse->getDecodeResponse(); + if (isset($taxData['data'])) { + $tax = $taxData['data']; + echo " Tax ID: " . (isset($tax['id']) ? $tax['id'] : $testTaxId) . "\n"; + echo " Name: " . (isset($tax['name']) ? $tax['name'] : 'N/A') . "\n"; + echo " Type: " . (isset($tax['type']) ? $tax['type'] : 'N/A') . "\n"; + echo " Value: " . (isset($tax['value']) ? $tax['value'] : 'N/A') . "\n"; + echo " Description: " . (isset($tax['description']) ? $tax['description'] : 'N/A') . "\n"; + } } else { - echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $getTaxResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -136,18 +140,21 @@ echo "5. Updating tax\n"; echo "---------------\n"; -$updateData = [ - 'value' => 0.085, - 'description' => 'Updated to 8.5% sales tax rate' +$updateTaxData = [ + 'name' => 'Updated Processing Fee', + 'description' => 'Updated processing fee with new rate', + 'value' => 3.00 ]; try { - $updateResponse = $businessGateway->eInvoiceTaxService()->updateTax($taxId, $updateData); + $updateResponse = $businessGateway->eInvoiceTaxService()->updateTax($testTaxId, $updateTaxData); if ($updateResponse->isSuccessful()) { echo "✓ Tax updated successfully\n"; - echo " New rate: " . ($updateData['value'] * 100) . "%\n"; - echo " Updated description: {$updateData['description']}\n"; + echo " Tax ID: " . $testTaxId . "\n"; + echo " Updated Name: " . $updateTaxData['name'] . "\n"; + echo " Updated Value: $" . number_format($updateTaxData['value'], 2) . "\n"; + echo " Updated Description: " . $updateTaxData['description'] . "\n"; } else { echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } @@ -157,33 +164,29 @@ echo "\n"; -// Example 6: List all taxes -echo "6. Listing all taxes\n"; -echo "--------------------\n"; +// Example 6: List taxes +echo "6. Listing taxes\n"; +echo "----------------\n"; + +$filters = [ + 'limit' => 10, + 'offset' => 0 +]; try { - $listResponse = $businessGateway->eInvoiceTaxService()->listTaxes(); + $listResponse = $businessGateway->eInvoiceTaxService()->listTaxes($filters); if ($listResponse->isSuccessful()) { - echo "✓ Tax list retrieved\n"; + echo "✓ Tax list retrieved successfully\n"; $listData = $listResponse->getDecodeResponse(); - $taxes = $listData['data']['data'] ?? []; - - echo " Total taxes: " . count($taxes) . "\n"; - - if (!empty($taxes)) { - echo " Configured taxes:\n"; - foreach ($taxes as $tax) { - $id = $tax['id'] ?? 'Unknown'; - $name = $tax['name'] ?? 'Unnamed'; - $type = $tax['type'] ?? 'N/A'; - $value = $tax['value'] ?? 0; - - if ($type === 'percentage') { - echo " - $name ($id): $value% ($type)\n"; - } else { - echo " - $name ($id): " . ($value * 100) . "% ($type)\n"; - } + if (isset($listData['data']) && is_array($listData['data'])) { + echo " Found " . count($listData['data']) . " taxes:\n"; + foreach ($listData['data'] as $tax) { + $id = isset($tax['id']) ? $tax['id'] : 'Unknown'; + $name = isset($tax['name']) ? $tax['name'] : 'Unnamed'; + $type = isset($tax['type']) ? $tax['type'] : 'Unknown'; + $value = isset($tax['value']) ? $tax['value'] : '0'; + echo " - " . $name . " (" . $id . ") - " . $type . ": " . $value . "\n"; } } } else { @@ -195,28 +198,20 @@ echo "\n"; -// Example 7: Create zero tax (tax-exempt) -echo "7. Creating tax-exempt option\n"; -echo "-----------------------------\n"; +// Example 7: Delete tax +echo "7. Deleting tax\n"; +echo "---------------\n"; -$zeroTaxData = [ - 'name' => 'Tax Exempt', - 'type' => 'flat', - 'value' => 0, - 'description' => 'No tax applied - tax exempt status' -]; +$deleteTestTaxId = isset($vatTaxId) ? $vatTaxId : 'TX-DELETE-' . time(); try { - $zeroTaxResponse = $businessGateway->eInvoiceTaxService()->createTax($zeroTaxData); - - if ($zeroTaxResponse->isSuccessful()) { - echo "✓ Tax-exempt option created successfully\n"; - $responseData = $zeroTaxResponse->getDecodeResponse(); - $zeroTaxId = $responseData['data']['id'] ?? 'TX-EXEMPT-' . time(); - echo " Tax ID: $zeroTaxId\n"; - echo " Rate: 0% (tax exempt)\n"; + $deleteResponse = $businessGateway->eInvoiceTaxService()->deleteTax($deleteTestTaxId); + + if ($deleteResponse->isSuccessful()) { + echo "✓ Tax deleted successfully\n"; + echo " Deleted Tax ID: " . $deleteTestTaxId . "\n"; } else { - echo "✗ Error: " . $zeroTaxResponse->getErrors()->getMessage() . "\n"; + echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "✗ Exception: " . $e->getMessage() . "\n"; @@ -224,58 +219,144 @@ echo "\n"; -// Example 8: Create multiple regional taxes -echo "8. Creating regional tax variations\n"; -echo "-----------------------------------\n"; - -$regionalTaxes = [ - [ - 'name' => 'California Sales Tax', - 'type' => 'flat', - 'value' => 0.0725, - 'description' => '7.25% California state sales tax' +// Example 8: Using taxes in invoices (embedded tax object) +echo "8. Using taxes in invoices\n"; +echo "--------------------------\n"; + +$invoiceWithTaxData = [ + 'currency' => 'USD', + 'summary' => 'Invoice with embedded tax', + 'number' => 'INV-TAX-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => 'CT-250527-AZARCIJE', + 'tax' => [ + 'name' => 'Service Tax', + 'type' => 'percentage', + 'value' => 5, + 'description' => '5% service tax' ], - [ - 'name' => 'New York Sales Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% New York state sales tax' - ], - [ - 'name' => 'Texas Sales Tax', - 'type' => 'flat', - 'value' => 0.0625, - 'description' => '6.25% Texas state sales tax' + 'items' => [ + [ + 'price' => 100.00, + 'quantity' => 1, + 'name' => 'Consulting Service', + 'description' => 'Professional consulting service' + ] ] ]; -$createdRegionalTaxes = []; - -foreach ($regionalTaxes as $taxData) { - try { - $response = $businessGateway->eInvoiceTaxService()->createTax($taxData); +try { + $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceWithTaxData); + + if ($invoiceResponse->isSuccessful()) { + echo "✓ Invoice with embedded tax created successfully\n"; + $responseData = $invoiceResponse->getDecodeResponse(); + $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Invoice Number: " . $invoiceWithTaxData['number'] . "\n"; + echo " Tax: " . $invoiceWithTaxData['tax']['name'] . " (" . $invoiceWithTaxData['tax']['value'] . "%)\n"; + } else { + echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} => 0 +); - if ($response->isSuccessful()) { - $responseData = $response->getDecodeResponse(); - $taxId = $responseData['data']['id'] ?? 'TX-REGIONAL-' . time(); - $createdRegionalTaxes[] = $taxId; +try { + $listResponse = $businessGateway->eInvoiceTaxService()->listTaxes($filters); - echo "✓ {$taxData['name']}: " . ($taxData['value'] * 100) . "% (ID: $taxId)\n"; - } else { - echo "✗ Failed to create {$taxData['name']}: " . $response->getErrors()->getMessage() . "\n"; + if ($listResponse->isSuccessful()) { + echo "✓ Tax list retrieved successfully\n"; + $listData = $listResponse->getDecodeResponse(); + if (isset($listData['data']) && is_array($listData['data'])) { + echo " Found " . count($listData['data']) . " taxes:\n"; + foreach ($listData['data'] as $tax) { + $id = isset($tax['id']) ? $tax['id'] : 'Unknown'; + $name = isset($tax['name']) ? $tax['name'] : 'Unnamed'; + $type = isset($tax['type']) ? $tax['type'] : 'Unknown'; + $value = isset($tax['value']) ? $tax['value'] : '0'; + echo " - " . $name . " (" . $id . ") - " . $type . ": " . $value . "\n"; + } } - } catch (FasterPay\Exception $e) { - echo "✗ Exception creating {$taxData['name']}: " . $e->getMessage() . "\n"; + } else { + echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + +// Example 7: Delete tax +echo "7. Deleting tax\n"; +echo "---------------\n"; + +$deleteTestTaxId = isset($vatTaxId) ? $vatTaxId : 'TX-DELETE-' . time(); + +try { + $deleteResponse = $businessGateway->eInvoiceTaxService()->deleteTax($deleteTestTaxId); + + if ($deleteResponse->isSuccessful()) { + echo "✓ Tax deleted successfully\n"; + echo " Deleted Tax ID: " . $deleteTestTaxId . "\n"; + } else { + echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; } -echo " Created " . count($createdRegionalTaxes) . " regional tax configurations\n"; +echo "\n"; + +// Example 8: Using taxes in invoices (embedded tax object) +echo "8. Using taxes in invoices\n"; +echo "--------------------------\n"; + +$invoiceWithTaxData = array( + 'currency' => 'USD', + 'summary' => 'Invoice with embedded tax', + 'number' => 'INV-TAX-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => 'CT-250527-AZARCIJE', + 'tax' => array( + 'name' => 'Service Tax', + 'type' => 'percentage', + 'value' => 5, + 'description' => '5% service tax' + ), + 'items' => array( + array( + 'price' => 100.00, + 'quantity' => 1, + 'name' => 'Consulting Service', + 'description' => 'Professional consulting service' + ) + ) +); + +try { + $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceWithTaxData); + + if ($invoiceResponse->isSuccessful()) { + echo "✓ Invoice with embedded tax created successfully\n"; + $responseData = $invoiceResponse->getDecodeResponse(); + $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); + echo " Invoice ID: " . $invoiceId . "\n"; + echo " Invoice Number: " . $invoiceWithTaxData['number'] . "\n"; + echo " Tax: " . $invoiceWithTaxData['tax']['name'] . " (" . $invoiceWithTaxData['tax']['value'] . "%)\n"; + } else { + echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "✗ Exception: " . $e->getMessage() . "\n"; +} echo "\nE-Invoice Tax API examples completed!\n"; echo "Use cases:\n"; -echo "• Multi-jurisdictional tax compliance\n"; -echo "• Automated tax calculation\n"; -echo "• Regional tax rate management\n"; -echo "• Tax-exempt transaction handling\n"; -echo "• VAT/GST compliance for international sales\n"; -echo "• Dynamic tax rate updates\n"; \ No newline at end of file +echo "• Sales tax calculation and management\n"; +echo "• VAT handling for international transactions\n"; +echo "• Fixed processing fees\n"; +echo "• State and local tax compliance\n"; +echo "• Custom tax rates per region\n"; +echo "• Tax exemption handling\n"; +echo "• Multi-jurisdiction tax support\n"; +echo "• Automated tax calculation in invoices\n"; \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Discount.php b/lib/FasterPay/Services/Business/EInvoice/Discount.php index a84f891..c0dc051 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Discount.php +++ b/lib/FasterPay/Services/Business/EInvoice/Discount.php @@ -15,46 +15,9 @@ class Discount extends GeneralService * * @param array $params Discount parameters * @return GeneralResponse - * @throws Exception */ - public function createDiscount(array $params = []) + public function createDiscount(array $params = array()) { - if (empty($params['name'])) { - throw new Exception('Discount name is required'); - } - - if (empty($params['type'])) { - throw new Exception('Discount type is required'); - } - - if (!isset($params['value']) || !is_numeric($params['value'])) { - throw new Exception('Discount value is required and must be numeric'); - } - - // Validate discount type - $validTypes = ['flat', 'percentage']; - if (!in_array($params['type'], $validTypes)) { - throw new Exception('Discount type must be either "flat" or "percentage"'); - } - - // Validate value based on type - if ($params['type'] === 'percentage' && ($params['value'] < 0 || $params['value'] > 100)) { - throw new Exception('Percentage discount value must be between 0 and 100'); - } - - if ($params['type'] === 'flat' && $params['value'] < 0) { - throw new Exception('Flat discount value must be non-negative'); - } - - // Validate currency for flat discounts - if ($params['type'] === 'flat' && empty($params['currency'])) { - throw new Exception('Currency is required for flat discount type'); - } - - if (!empty($params['currency']) && strlen($params['currency']) !== 3) { - throw new Exception('Currency must be 3 characters (ISO 4217)'); - } - $endpoint = $this->httpService->getEndPoint($this->endpoint); $response = $this->httpService->getHttpClient()->post($endpoint, $params); @@ -90,7 +53,18 @@ public function getDiscount($discountId = '') * @return GeneralResponse * @throws Exception */ - public function updateDiscount($discountId = '', array $params = []) + public function updateDiscount($discountId = '', array $params = array()) + { + if (empty($discountId)) { + throw new Exception('Discount ID is required'); + } + + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $discountId); + + $response = $this->httpService->getHttpClient()->put($endpoint, $params); + + return new GeneralResponse($response); + } array $params = array()) { if (empty($discountId)) { throw new Exception('Discount ID is required'); @@ -98,7 +72,7 @@ public function updateDiscount($discountId = '', array $params = []) // Validate discount type if provided if (!empty($params['type'])) { - $validTypes = ['flat', 'percentage']; + $validTypes = array('flat', 'percentage'); if (!in_array($params['type'], $validTypes)) { throw new Exception('Discount type must be either "flat" or "percentage"'); } @@ -121,9 +95,11 @@ public function updateDiscount($discountId = '', array $params = []) } } - // Validate currency if provided - if (!empty($params['currency']) && strlen($params['currency']) !== 3) { - throw new Exception('Currency must be 3 characters (ISO 4217)'); + // Validate currency for flat discounts + if (!empty($params['type']) && $params['type'] === 'flat' && !empty($params['currency'])) { + if (strlen($params['currency']) !== 3) { + throw new Exception('Currency must be 3 characters (ISO 4217)'); + } } $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $discountId); @@ -159,7 +135,7 @@ public function deleteDiscount($discountId = '') * @param array $filters Optional filters * @return GeneralResponse */ - public function listDiscounts(array $filters = []) + public function listDiscounts(array $filters = array()) { $endpoint = $this->httpService->getEndPoint($this->endpoint); diff --git a/lib/FasterPay/Services/Business/EInvoice/Tax.php b/lib/FasterPay/Services/Business/EInvoice/Tax.php index 89c32a0..5326cb1 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Tax.php +++ b/lib/FasterPay/Services/Business/EInvoice/Tax.php @@ -15,37 +15,9 @@ class Tax extends GeneralService * * @param array $params Tax parameters * @return GeneralResponse - * @throws Exception */ public function createTax(array $params = []) { - if (empty($params['name'])) { - throw new Exception('Tax name is required'); - } - - if (empty($params['type'])) { - throw new Exception('Tax type is required'); - } - - if (!isset($params['value']) || !is_numeric($params['value'])) { - throw new Exception('Tax value is required and must be numeric'); - } - - // Validate tax type - $validTypes = ['flat', 'percentage']; - if (!in_array($params['type'], $validTypes)) { - throw new Exception('Tax type must be either "flat" or "percentage"'); - } - - // Validate value based on type - if ($params['type'] === 'percentage' && ($params['value'] < 0 || $params['value'] > 100)) { - throw new Exception('Percentage tax value must be between 0 and 100'); - } - - if ($params['type'] === 'flat' && $params['value'] < 0) { - throw new Exception('Flat tax value must be non-negative'); - } - $endpoint = $this->httpService->getEndPoint($this->endpoint); $response = $this->httpService->getHttpClient()->post($endpoint, $params); @@ -87,31 +59,6 @@ public function updateTax($taxId = '', array $params = []) throw new Exception('Tax ID is required'); } - // Validate tax type if provided - if (!empty($params['type'])) { - $validTypes = ['flat', 'percentage']; - if (!in_array($params['type'], $validTypes)) { - throw new Exception('Tax type must be either "flat" or "percentage"'); - } - } - - // Validate value if provided - if (isset($params['value'])) { - if (!is_numeric($params['value'])) { - throw new Exception('Tax value must be numeric'); - } - - if (!empty($params['type'])) { - if ($params['type'] === 'percentage' && ($params['value'] < 0 || $params['value'] > 100)) { - throw new Exception('Percentage tax value must be between 0 and 100'); - } - - if ($params['type'] === 'flat' && $params['value'] < 0) { - throw new Exception('Flat tax value must be non-negative'); - } - } - } - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $taxId); $response = $this->httpService->getHttpClient()->put($endpoint, $params); From e2fd26dd3289eabdffe0408c94af0f363a697a8a Mon Sep 17 00:00:00 2001 From: James Date: Wed, 6 Aug 2025 11:24:28 +0700 Subject: [PATCH 06/20] update --- code-samples/business/payout.php | 143 ++++++++++----------- lib/FasterPay/Services/Business/Payout.php | 101 +-------------- 2 files changed, 67 insertions(+), 177 deletions(-) diff --git a/code-samples/business/payout.php b/code-samples/business/payout.php index 3ece328..0edebf1 100644 --- a/code-samples/business/payout.php +++ b/code-samples/business/payout.php @@ -5,10 +5,15 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1, + 'isTest' => 1 ]); -// Example 1: Create mass payout +echo "=== FasterPay Mass Payout API Examples ===\n\n"; + +// Example 1: Create mass payout following API documentation +echo "1. Creating mass payout\n"; +echo "-----------------------\n"; + $massPayoutParams = [ 'source_currency' => 'USD', 'template' => 'wallet', @@ -27,35 +32,28 @@ 'amount' => '75.50', 'amount_currency' => 'USD', 'target_currency' => 'USD', - 'receiver_full_name' => 'Jane Smith', + 'receiver_full_name' => 'Jane Smith Corporation', 'receiver_email' => 'jane@example.com', - 'receiver_type' => 'private' - ], - [ - 'reference_id' => 'payout_003', - 'amount' => '200.25', - 'amount_currency' => 'USD', - 'target_currency' => 'USD', - 'receiver_full_name' => 'Bob Johnson', - 'receiver_email' => 'bob@example.com', 'receiver_type' => 'business' ] ] ]; +$createdPayoutIds = []; + try { - $massPayoutResponse = $businessGateway->massPayoutService()->createPayout($massPayoutParams); + $massPayoutResponse = $businessGateway->payoutService()->createPayout($massPayoutParams); if ($massPayoutResponse->isSuccessful()) { echo "Mass payout created successfully\n"; - echo "Response: " . $massPayoutResponse->getRawResponse() . "\n"; - - // Extract payout ID from response for further operations $responseData = $massPayoutResponse->getDecodeResponse(); - $payoutId = $responseData['payout_id'] ?? null; - - if ($payoutId) { - echo "Payout ID: " . $payoutId . "\n"; + + // Extract payout IDs from response for further operations + if (isset($responseData['data']['payouts']) && is_array($responseData['data']['payouts'])) { + foreach ($responseData['data']['payouts'] as $payoutItem) { + $createdPayoutIds[] = $payoutItem['id']; + echo "Payout ID: " . $payoutItem['id'] . " - Status: " . $payoutItem['status'] . "\n"; + } } } else { echo "Error: " . $massPayoutResponse->getErrors()->getMessage() . "\n"; @@ -64,82 +62,71 @@ echo "Exception: " . $e->getMessage() . "\n"; } -// Example 2: Get payout details -$payoutId = ''; - -try { - $payoutDetails = $businessGateway->massPayoutService()->getPayoutDetails($payoutId); - - if ($payoutDetails->isSuccessful()) { - echo "Payout details retrieved successfully\n"; - echo "Details: " . $payoutDetails->getRawResponse() . "\n"; - } else { - echo "Error: " . $payoutDetails->getErrors()->getMessage() . "\n"; +echo "\n"; + +// Example 2: Get payout details using ID from create response +echo "2. Getting payout details\n"; +echo "-------------------------\n"; + +if (!empty($createdPayoutIds)) { + $payoutId = $createdPayoutIds[0]; // Use first created payout ID + echo "Using payout ID from create response: " . $payoutId . "\n"; + + try { + $payoutDetails = $businessGateway->payoutService()->getPayoutDetails($payoutId); + + if ($payoutDetails->isSuccessful()) { + echo "Payout details retrieved successfully\n"; + $responseData = $payoutDetails->getDecodeResponse(); + + if (isset($responseData['data'])) { + $data = $responseData['data']; + echo "Payout ID: " . $data['id'] . "\n"; + echo "Status: " . $data['status'] . "\n"; + echo "Receiver: " . $data['receiver_full_name'] . " (" . $data['receiver_email'] . ")\n"; + echo "Amount: " . $data['amounts']['target_amount'] . " " . $data['amounts']['target_currency'] . "\n"; + } + } else { + echo "Error: " . $payoutDetails->getErrors()->getMessage() . "\n"; + } + } catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; +} else { + echo "No payout ID available from previous create operation\n"; } +echo "\n"; + // Example 3: Get payout list with filters +echo "3. Getting payout list with filters\n"; +echo "-----------------------------------\n"; + $filters = [ 'limit' => 20, 'offset' => 0, - 'status' => 'pending', + 'status' => 'submitted', 'from_date' => '2024-01-01', 'to_date' => '2024-12-31' ]; try { - $payoutList = $businessGateway->massPayoutService()->getPayoutList($filters); + $payoutList = $businessGateway->payoutService()->getPayoutList($filters); if ($payoutList->isSuccessful()) { echo "Payout list retrieved successfully\n"; - echo "List: " . $payoutList->getRawResponse() . "\n"; + $responseData = $payoutList->getDecodeResponse(); + + if (isset($responseData['data']['payouts']) && is_array($responseData['data']['payouts'])) { + echo "Found " . count($responseData['data']['payouts']) . " payouts\n"; + foreach ($responseData['data']['payouts'] as $payout) { + echo "- " . $payout['id'] . " (" . $payout['status'] . ") - " . + $payout['amounts']['target_amount'] . " " . $payout['amounts']['target_currency'] . "\n"; + } + } } else { echo "Error: " . $payoutList->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; -} - -// Example 4: Get payout status -try { - $payoutStatus = $businessGateway->massPayoutService()->getPayoutStatus($payoutId); - - if ($payoutStatus->isSuccessful()) { - echo "Payout status retrieved successfully\n"; - echo "Status: " . $payoutStatus->getRawResponse() . "\n"; - } else { - echo "Error: " . $payoutStatus->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -// Example 5: Cancel payout (if still pending) -try { - $cancelResponse = $businessGateway->massPayoutService()->cancelPayout($payoutId); - - if ($cancelResponse->isSuccessful()) { - echo "Payout cancelled successfully\n"; - echo "Response: " . $cancelResponse->getRawResponse() . "\n"; - } else { - echo "Error: " . $cancelResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -// Example 6: Retry failed payout -try { - $retryResponse = $businessGateway->massPayoutService()->retryPayout($payoutId); - - if ($retryResponse->isSuccessful()) { - echo "Payout retry initiated successfully\n"; - echo "Response: " . $retryResponse->getRawResponse() . "\n"; - } else { - echo "Error: " . $retryResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; } \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/Payout.php b/lib/FasterPay/Services/Business/Payout.php index 3d9c35b..59ed1db 100644 --- a/lib/FasterPay/Services/Business/Payout.php +++ b/lib/FasterPay/Services/Business/Payout.php @@ -15,46 +15,9 @@ class Payout extends GeneralService * * @param array $params Payout parameters * @return GeneralResponse - * @throws Exception */ - public function createPayout(array $params = []) + public function createPayout($params = []) { - if (empty($params['payouts']) || !is_array($params['payouts'])) { - throw new Exception('Payouts array is required'); - } - - if (empty($params['source_currency'])) { - throw new Exception('Source currency is required'); - } - - if (empty($params['template'])) { - throw new Exception('Template is required'); - } - - // Validate each payout - foreach ($params['payouts'] as $payout) { - if (empty($payout['receiver_email'])) { - throw new Exception('Each payout must have a receiver_email'); - } - if (empty($payout['amount'])) { - throw new Exception('Each payout must have an amount'); - } - if (empty($payout['amount_currency'])) { - throw new Exception('Each payout must have an amount_currency'); - } - if (empty($payout['receiver_full_name'])) { - throw new Exception('Each payout must have a receiver_full_name'); - } - if (empty($payout['receiver_type'])) { - throw new Exception('Each payout must have a receiver_type'); - } - - // Validate receiver_type - if (!in_array($payout['receiver_type'], ['private', 'business'])) { - throw new Exception('Receiver type must be either "private" or "business"'); - } - } - $endpoint = $this->httpService->getEndPoint($this->endpoint); $response = $this->httpService->getHttpClient()->post($endpoint, $params); @@ -88,7 +51,7 @@ public function getPayoutDetails($payoutId = '') * @param array $filters Optional filters (limit, offset, status, etc.) * @return GeneralResponse */ - public function getPayoutList(array $filters = []) + public function getPayoutList($filters = []) { $endpoint = $this->httpService->getEndPoint($this->endpoint); @@ -96,64 +59,4 @@ public function getPayoutList(array $filters = []) return new GeneralResponse($response); } - - /** - * Cancel a payout - * - * @param string $payoutId Payout ID - * @return GeneralResponse - * @throws Exception - */ - public function cancelPayout($payoutId = '') - { - if (empty($payoutId)) { - throw new Exception('Payout ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $payoutId . '/cancel'); - - $response = $this->httpService->getHttpClient()->post($endpoint); - - return new GeneralResponse($response); - } - - /** - * Get payout status - * - * @param string $payoutId Payout ID - * @return GeneralResponse - * @throws Exception - */ - public function getPayoutStatus($payoutId = '') - { - if (empty($payoutId)) { - throw new Exception('Payout ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $payoutId . '/status'); - - $response = $this->httpService->getHttpClient()->get($endpoint); - - return new GeneralResponse($response); - } - - /** - * Retry a failed payout - * - * @param string $payoutId Payout ID - * @return GeneralResponse - * @throws Exception - */ - public function retryPayout($payoutId = '') - { - if (empty($payoutId)) { - throw new Exception('Payout ID is required'); - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $payoutId . '/retry'); - - $response = $this->httpService->getHttpClient()->post($endpoint); - - return new GeneralResponse($response); - } } \ No newline at end of file From d42b84d7a882bba2b58d2bfb88671404228fcf4f Mon Sep 17 00:00:00 2001 From: James Date: Wed, 6 Aug 2025 19:06:20 +0700 Subject: [PATCH 07/20] update --- code-samples/business/address.php | 1 - code-samples/business/contact.php | 4 +- code-samples/business/e-invoice/discount.php | 119 +- code-samples/business/e-invoice/invoice.php | 1423 ++++------------- code-samples/business/e-invoice/product.php | 298 ++-- code-samples/business/e-invoice/tax.php | 380 ++--- code-samples/business/e-invoice/template.php | 274 ++-- code-samples/business/payout.php | 30 +- lib/FasterPay/BusinessGateway.php | 20 +- lib/FasterPay/Response/JsonResponse.php | 48 + .../Services/Business/EInvoice/Discount.php | 43 - lib/FasterPay/Services/Business/Payout.php | 18 +- 12 files changed, 829 insertions(+), 1829 deletions(-) create mode 100644 lib/FasterPay/Response/JsonResponse.php diff --git a/code-samples/business/address.php b/code-samples/business/address.php index d438712..e1c2bc8 100644 --- a/code-samples/business/address.php +++ b/code-samples/business/address.php @@ -5,7 +5,6 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1, ]); echo "FasterPay Address API Examples\n"; diff --git a/code-samples/business/contact.php b/code-samples/business/contact.php index 7f6cec8..4962050 100644 --- a/code-samples/business/contact.php +++ b/code-samples/business/contact.php @@ -5,7 +5,6 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1, ]); echo "FasterPay Contact API Examples\n"; @@ -113,7 +112,8 @@ echo "-------------------------------\n"; $updateData = [ - 'phone' => '2015559999', + 'phone' => '2015550125', + 'phone_country_code' => 'US', 'favorite' => false, 'first_name' => 'Jonathan' ]; diff --git a/code-samples/business/e-invoice/discount.php b/code-samples/business/e-invoice/discount.php index 45e207a..0a74b8d 100644 --- a/code-samples/business/e-invoice/discount.php +++ b/code-samples/business/e-invoice/discount.php @@ -5,10 +5,9 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1, ]); -echo "FasterPay E-Invoice Discount API Examples\n"; +echo "FasterPay Invoice Discount API Examples\n"; echo "==========================================\n\n"; // Example 1: Create a flat discount @@ -24,7 +23,7 @@ ]; try { - $discountResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($flatDiscountData); + $discountResponse = $businessGateway->invoiceDiscountService()->createDiscount($flatDiscountData); if ($discountResponse->isSuccessful()) { echo "✓ Flat discount created successfully\n"; @@ -56,7 +55,7 @@ ]; try { - $volumeResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($percentageDiscountData); + $volumeResponse = $businessGateway->invoiceDiscountService()->createDiscount($percentageDiscountData); if ($volumeResponse->isSuccessful()) { echo "✓ Percentage discount created successfully\n"; @@ -88,7 +87,7 @@ ]; try { - $loyaltyResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($loyaltyDiscountData); + $loyaltyResponse = $businessGateway->invoiceDiscountService()->createDiscount($loyaltyDiscountData); if ($loyaltyResponse->isSuccessful()) { echo "✓ Loyalty discount created successfully\n"; @@ -115,7 +114,7 @@ $testDiscountId = isset($discountId) ? $discountId : 'DC-250527-WZX0'; try { - $getDiscountResponse = $businessGateway->eInvoiceDiscountService()->getDiscount($testDiscountId); + $getDiscountResponse = $businessGateway->invoiceDiscountService()->getDiscount($testDiscountId); if ($getDiscountResponse->isSuccessful()) { echo "✓ Discount details retrieved successfully\n"; @@ -151,7 +150,7 @@ ]; try { - $updateResponse = $businessGateway->eInvoiceDiscountService()->updateDiscount($testDiscountId, $updateDiscountData); + $updateResponse = $businessGateway->invoiceDiscountService()->updateDiscount($testDiscountId, $updateDiscountData); if ($updateResponse->isSuccessful()) { echo "✓ Discount updated successfully\n"; @@ -178,14 +177,14 @@ ]; try { - $listResponse = $businessGateway->eInvoiceDiscountService()->listDiscounts($filters); + $listResponse = $businessGateway->invoiceDiscountService()->listDiscounts($filters); if ($listResponse->isSuccessful()) { echo "✓ Discount list retrieved successfully\n"; $listData = $listResponse->getDecodeResponse(); - if (isset($listData['data']) && is_array($listData['data'])) { - echo " Found " . count($listData['data']) . " discounts:\n"; - foreach ($listData['data'] as $discount) { + if (isset($listData['data']['data']) && is_array($listData['data']['data'])) { + echo " Found " . count($listData['data']['data']) . " discounts:\n"; + foreach ($listData['data']['data'] as $discount) { $id = isset($discount['id']) ? $discount['id'] : 'Unknown'; $name = isset($discount['name']) ? $discount['name'] : 'Unnamed'; $type = isset($discount['type']) ? $discount['type'] : 'Unknown'; @@ -210,7 +209,7 @@ $deleteTestDiscountId = isset($loyaltyDiscountId) ? $loyaltyDiscountId : 'DC-DELETE-' . time(); try { - $deleteResponse = $businessGateway->eInvoiceDiscountService()->deleteDiscount($deleteTestDiscountId); + $deleteResponse = $businessGateway->invoiceDiscountService()->deleteDiscount($deleteTestDiscountId); if ($deleteResponse->isSuccessful()) { echo "✓ Discount deleted successfully\n"; @@ -224,101 +223,7 @@ echo "\n"; -// Example 8: Using discounts in invoices (embedded discount object) -echo "8. Using discounts in invoices\n"; -echo "------------------------------\n"; - -$invoiceWithDiscountData = [ - 'currency' => 'USD', - 'summary' => 'Invoice with embedded discount', - 'number' => 'INV-DISC-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => 'CT-250527-AZARCIJE', - 'discount' => [ - 'name' => 'Seasonal Discount', - 'type' => 'percentage', - 'value' => 20, - 'description' => '20% seasonal discount' - ], - 'items' => [ - [ - 'price' => 200.00, - 'quantity' => 1, - 'name' => 'Premium Service Package', - 'description' => 'Comprehensive service package' - ] - ] -]; - -try { - $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceWithDiscountData); - - if ($invoiceResponse->isSuccessful()) { - echo "✓ Invoice with embedded discount created successfully\n"; - $responseData = $invoiceResponse->getDecodeResponse(); - $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Invoice Number: " . $invoiceWithDiscountData['number'] . "\n"; - echo " Discount: " . $invoiceWithDiscountData['discount']['name'] . " (" . $invoiceWithDiscountData['discount']['value'] . "%)\n"; - } else { - echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 9: Create invoice with both tax and discount -echo "9. Creating invoice with tax and discount\n"; -echo "-----------------------------------------\n"; - -$combinedInvoiceData = [ - 'currency' => 'USD', - 'summary' => 'Invoice with tax and discount', - 'number' => 'INV-COMBO-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => 'CT-250527-AZARCIJE', - 'tax' => [ - 'name' => 'Sales Tax', - 'type' => 'percentage', - 'value' => 8.5, - 'description' => '8.5% sales tax' - ], - 'discount' => [ - 'name' => 'First Time Customer', - 'type' => 'flat', - 'value' => 25.00, - 'currency' => 'USD', - 'description' => '$25 discount for first-time customers' - ], - 'items' => [ - [ - 'price' => 500.00, - 'quantity' => 1, - 'name' => 'Professional Services', - 'description' => 'Complete professional service package' - ] - ] -]; - -try { - $comboResponse = $businessGateway->eInvoiceService()->createInvoice($combinedInvoiceData); - - if ($comboResponse->isSuccessful()) { - echo "✓ Invoice with tax and discount created successfully\n"; - $responseData = $comboResponse->getDecodeResponse(); - $comboInvoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); - echo " Invoice ID: " . $comboInvoiceId . "\n"; - echo " Invoice Number: " . $combinedInvoiceData['number'] . "\n"; - echo " Tax: " . $combinedInvoiceData['tax']['name'] . " (" . $combinedInvoiceData['tax']['value'] . "%)\n"; - echo " Discount: " . $combinedInvoiceData['discount']['name'] . " ($" . $combinedInvoiceData['discount']['value'] . ")\n"; - } else { - echo "✗ Error: " . $comboResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\nE-Invoice Discount API examples completed!\n"; +echo "\nInvoice Discount API examples completed!\n"; echo "Use cases:\n"; echo "• Early payment incentives\n"; echo "• Volume purchase discounts\n"; diff --git a/code-samples/business/e-invoice/invoice.php b/code-samples/business/e-invoice/invoice.php index 81dfdc5..7bae378 100644 --- a/code-samples/business/e-invoice/invoice.php +++ b/code-samples/business/e-invoice/invoice.php @@ -1,1209 +1,384 @@ '', 'privateKey' => '', - 'isTest' => 1, ]); echo "FasterPay E-Invoice API Examples\n"; echo "=================================\n\n"; -// Example 1: Create a new e-invoice with embedded components -echo "1. Creating a new e-invoice with embedded components\n"; -echo "----------------------------------------------------\n"; +$contactData = [ + 'email' => 'john.smith@example.com', + 'phone' => '2015550124', + 'phone_country_code' => 'US', + 'first_name' => 'John', + 'last_name' => 'Smith', + 'country' => 'US', + 'favorite' => true +]; + +$contactResponse = $businessGateway->contactService()->createContact($contactData); + +$responseData = $contactResponse->getDecodeResponse(); +$contactId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'CT-' . time(); + +try { + + // Example 1: Create invoice with embedded components + echo "1. Creating invoice with embedded components\n"; + echo "--------------------------------------------\n"; -$invoiceData = [ - 'currency' => 'USD', - 'summary' => 'Website development project invoice', - 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => 'CT-250527-AZARCIJE', - 'template' => [ - 'name' => 'Project Template', - 'footer' => 'Thank you for your business!', - 'colors' => [ - 'primary' => '#2563eb', - 'secondary' => '#f8fafc' + $invoiceData = [ + 'currency' => 'USD', + 'summary' => 'Website development project invoice', + 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => $contactId, + 'due_date' => date('Y-m-d', strtotime('+30 days')), + 'template' => [ + 'name' => 'Project Template', + 'footer' => 'Thank you for your business!', + 'colors' => [ + 'primary' => '#2563eb', + 'secondary' => '#f8fafc' + ], + 'localized_address' => [ + 'address_line1' => '123 Business Ave', + 'locality' => 'San Francisco', + 'administrative_area' => 'CA', + 'postal_code' => '94105' + ], + 'country_code' => 'US' ], - 'localized_address' => [ - 'address_line1' => '123 Business Ave', - 'locality' => 'San Francisco', - 'administrative_area' => 'CA', - 'postal_code' => '94105' + 'tax' => [ + 'name' => 'Sales Tax', + 'type' => 'flat', + 'value' => 0.08, + 'description' => '8% sales tax' ], - 'country_code' => 'US' - ], - 'tax' => [ - 'name' => 'Sales Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% sales tax' - ], - 'discount' => [ - 'name' => 'Early Payment', - 'type' => 'flat', - 'value' => 50.0, - 'currency' => 'USD', - 'description' => '$50 early payment discount' - ], - 'items' => [ - [ - 'price' => 2500.00, - 'quantity' => 1, - 'product' => [ - 'sku' => 'WEB-DEV-PROJ', - 'type' => 'digital', - 'name' => 'Website Development', - 'description' => 'Complete website development project', - 'prices' => [ - [ - 'price' => 2500.00, - 'currency' => 'USD' + 'discount' => [ + 'name' => 'Early Payment Discount', + 'type' => 'percentage', + 'value' => 10.0, + 'description' => '10% discount for early payment' + ], + 'items' => [ + [ + 'price' => 2500.00, + 'quantity' => 1, + 'product' => [ + 'sku' => 'WEB-DEV-001', + 'type' => 'digital', + 'name' => 'Website Development', + 'description' => 'Complete website development with responsive design', + 'prices' => [ + [ + 'price' => 2500.00, + 'currency' => 'USD' + ] ] + ], + 'tax' => [ + 'name' => 'Service Tax', + 'type' => 'percentage', + 'value' => 5.0 ] ], - 'tax' => [ - 'name' => 'Item Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% tax on this item' - ], - 'discount' => [ - 'name' => 'Item Discount', - 'type' => 'percentage', - 'value' => 5, - 'description' => '5% discount on this item' + [ + 'price' => 99.99, + 'quantity' => 12, + 'product' => [ + 'sku' => 'HOST-PREM-001', + 'type' => 'digital', + 'name' => 'Premium Hosting', + 'description' => 'Premium hosting with SSL and backups' + ] ] ] - ] -]; + ]; -try { - $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceData); + $response = $businessGateway->invoiceService()->createInvoice($invoiceData); - if ($invoiceResponse->isSuccessful()) { - echo "✓ E-invoice with embedded components created successfully\n"; - $responseData = $invoiceResponse->getDecodeResponse(); - $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); + if ($response->isSuccessful()) { + echo "✓ Invoice created successfully!\n"; + $data = $response->getDecodeResponse(); + $invoiceId = $data['data']['id']; echo " Invoice ID: " . $invoiceId . "\n"; - echo " Invoice Number: " . $invoiceData['number'] . "\n"; - echo " Currency: " . $invoiceData['currency'] . "\n"; - echo " Items: " . count($invoiceData['items']) . "\n"; - echo " Template: " . $invoiceData['template']['name'] . "\n"; - } else { - echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 2: Create template with logo file (if you have a logo file) -echo "2. Creating invoice template with logo\n"; -echo "--------------------------------------\n"; - -$templateData = [ - 'name' => 'Professional Template with Logo', - 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', - 'colors' => [ - 'primary' => '#2563eb', - 'secondary' => '#f8fafc' - ], - 'localized_address' => [ - 'address_line1' => '123 Business Avenue', - 'locality' => 'San Francisco', - 'administrative_area' => 'CA', - 'postal_code' => '94105' - ], - 'country_code' => 'US' - // Note: For file upload, you would add: 'logo' => '@/path/to/logo.png' -]; - -try { - $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); - - if ($templateResponse->isSuccessful()) { - echo "✓ Invoice template created successfully\n"; - $responseData = $templateResponse->getDecodeResponse(); - $templateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-' . time(); - echo " Template ID: " . $templateId . "\n"; - echo " Name: " . $templateData['name'] . "\n"; - echo " Primary Color: " . $templateData['colors']['primary'] . "\n"; - } else { - echo "✗ Error: " . $templateResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 3: Create tax -echo "3. Creating tax configuration\n"; -echo "-----------------------------\n"; - -$taxData = [ - 'name' => 'Sales Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% sales tax rate' -]; - -try { - $taxResponse = $businessGateway->eInvoiceTaxService()->createTax($taxData); - - if ($taxResponse->isSuccessful()) { - echo "✓ Tax created successfully\n"; - $responseData = $taxResponse->getDecodeResponse(); - $taxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-' . time(); - echo " Tax ID: " . $taxId . "\n"; - echo " Name: " . $taxData['name'] . "\n"; - echo " Type: " . $taxData['type'] . "\n"; - echo " Rate: " . ($taxData['value'] * 100) . "%\n"; - } else { - echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 4: Create discount -echo "4. Creating discount offer\n"; -echo "--------------------------\n"; - -$discountData = [ - 'name' => 'Early Bird Discount', - 'type' => 'flat', - 'value' => 50.0, - 'currency' => 'USD', - 'description' => '$50 discount for early payment' -]; - -try { - $discountResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($discountData); - - if ($discountResponse->isSuccessful()) { - echo "✓ Discount created successfully\n"; - $responseData = $discountResponse->getDecodeResponse(); - $discountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-' . time(); - echo " Discount ID: " . $discountId . "\n"; - echo " Name: " . $discountData['name'] . "\n"; - echo " Value: $" . $discountData['value'] . " " . $discountData['currency'] . "\n"; + echo " Invoice Number: " . $data['data']['number'] . "\n"; + echo " Status: " . $data['data']['status'] . "\n"; + echo " Currency: " . $data['data']['currency'] . "\n"; + echo " Items: " . count($data['data']['items']) . "\n\n"; } else { - echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; + echo "✗ Failed to create invoice\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; -// Example 5: Create product with image (if you have an image file) -echo "5. Creating product with image\n"; -echo "------------------------------\n"; + // Example 2: Create invoice using existing component IDs + echo "2. Creating invoice with existing component IDs\n"; + echo "-----------------------------------------------\n"; -$productData = [ - 'sku' => 'WEB-DEV-001', - 'type' => 'digital', - 'name' => 'Website Development Package', - 'description' => 'Complete website development with modern responsive design', - 'prices' => [ - [ - 'price' => 2500.00, - 'currency' => 'USD' + $simpleInvoiceData = [ + 'currency' => 'USD', + 'summary' => 'Consulting services invoice', + 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => $contactId, + 'invoice_template_id' => 'IT-250527-AWRO', + 'tax_id' => 'TX-250527-2E9N', + 'discount_id' => 'DC-250527-WZX0', + 'items' => [ + [ + 'product_id' => 'PD-250528-L5CC', + 'price' => 150.00, + 'quantity' => 10, + 'tax_id' => 'TX-250527-2E9N' + ] ] - ] - // Note: For file upload, you would add: 'image' => '@/path/to/product-image.jpg' -]; - -try { - $productResponse = $businessGateway->eInvoiceProductService()->createProduct($productData); - - if ($productResponse->isSuccessful()) { - echo "✓ Product created successfully\n"; - $responseData = $productResponse->getDecodeResponse(); - $productId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-' . time(); - echo " Product ID: " . $productId . "\n"; - echo " SKU: " . $productData['sku'] . "\n"; - echo " Name: " . $productData['name'] . "\n"; - echo " Type: " . $productData['type'] . "\n"; - } else { - echo "✗ Error: " . $productResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 6: Update invoice using POST with _method=PUT -echo "6. Updating invoice\n"; -echo "-------------------\n"; - -$invoiceId = isset($invoiceId) ? $invoiceId : 'FPBIV-' . time(); -$updateData = [ - 'summary' => 'Updated website development project invoice', - 'template' => [ - 'footer' => 'Updated footer - Thank you for choosing our services!' - ] -]; - -try { - $updateResponse = $businessGateway->eInvoiceService()->updateInvoice($invoiceId, $updateData); - - if ($updateResponse->isSuccessful()) { - echo "✓ Invoice updated successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Updated summary and template footer\n"; - } else { - echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 7: Update invoice status -echo "7. Updating invoice status\n"; -echo "--------------------------\n"; - -$statusParams = [ - 'status' => 'sent', - 'notes' => 'Invoice sent to customer via email' -]; - -try { - $statusResponse = $businessGateway->eInvoiceService()->updateInvoiceStatus($invoiceId, $statusParams); + ]; - if ($statusResponse->isSuccessful()) { - echo "✓ Invoice status updated successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " New status: " . $statusParams['status'] . "\n"; - echo " Notes: " . $statusParams['notes'] . "\n"; - } else { - echo "✗ Error: " . $statusResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 8: Preview invoice (HTML) -echo "8. Previewing invoice HTML\n"; -echo "--------------------------\n"; - -try { - $previewResponse = $businessGateway->eInvoiceService()->previewInvoice($invoiceId); - - if ($previewResponse->isSuccessful()) { - echo "✓ Invoice preview generated successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Preview format: HTML\n"; - echo " (HTML content received - can be displayed in browser)\n"; - } else { - echo "✗ Error: " . $previewResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 9: Send invoice to customer -echo "9. Sending invoice to customer\n"; -echo "------------------------------\n"; - -$sendParams = [ - 'test' => false // According to API docs, main parameter is 'test' -]; - -try { - $sendResponse = $businessGateway->eInvoiceService()->sendInvoice($invoiceId, $sendParams); + $response = $businessGateway->invoiceService()->createInvoice($simpleInvoiceData); - if ($sendResponse->isSuccessful()) { - echo "✓ Invoice sent successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Sent to customer's email address\n"; + if ($response->isSuccessful()) { + echo "✓ Simple invoice created successfully!\n"; + $data = $response->getDecodeResponse(); + $simpleInvoiceId = $data['data']['id']; + echo " Invoice ID: " . $simpleInvoiceId . "\n\n"; } else { - echo "✗ Error: " . $sendResponse->getErrors()->getMessage() . "\n"; + echo "✗ Failed to create simple invoice\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; -// Example 10: Download invoice PDF (file response) -echo "10. Downloading invoice PDF\n"; -echo "---------------------------\n"; - -try { - // downloadInvoicePdf returns raw file data, not GeneralResponse - $downloadResponse = $businessGateway->eInvoiceService()->downloadInvoicePdf($invoiceId); - - if ($downloadResponse['httpCode'] == 200) { - echo "✓ Invoice PDF downloaded successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Content-Length: " . strlen($downloadResponse['response']) . " bytes\n"; - echo " Content-Type: PDF\n"; - - // In a real application, you would save this to a file: - // $filename = 'invoice_' . $invoiceId . '.pdf'; - // file_put_contents($filename, $downloadResponse['response']); - // echo " Saved as: " . $filename . "\n"; - - echo " (File content received - would be saved as PDF in real application)\n"; - } else { - echo "✗ Error downloading PDF: HTTP " . $downloadResponse['httpCode'] . "\n"; - if (!empty($downloadResponse['response'])) { - // Try to decode error response - $errorData = json_decode($downloadResponse['response'], true); - if ($errorData && isset($errorData['message'])) { - echo " Error message: " . $errorData['message'] . "\n"; - } + // Example 3: Get invoice details + echo "3. Getting invoice details\n"; + echo "--------------------------\n"; + + if (isset($invoiceId)) { + $response = $businessGateway->invoiceService()->getInvoice($invoiceId, ['include' => 'prices']); + + if ($response->isSuccessful()) { + $data = $response->getDecodeResponse(); + $invoice = $data['data']; + echo "✓ Invoice details retrieved successfully!\n"; + echo " ID: " . $invoice['id'] . "\n"; + echo " Status: " . $invoice['status'] . "\n"; + echo " Currency: " . $invoice['currency'] . "\n"; + echo " Summary: " . $invoice['summary'] . "\n"; + echo " Due Date: " . $invoice['due_date'] . "\n"; + echo " Items Count: " . count($invoice['items']) . "\n\n"; + } else { + echo "✗ Failed to get invoice details\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Invoice status handling via pingbacks (documentation example) -echo "Invoice status handling via pingbacks\n"; -echo "-------------------------------------\n"; - -echo "✓ Invoice status changes are handled via pingbacks\n"; -echo " Pingback example from API documentation:\n"; -echo " {\n"; -echo " \"event\": \"invoice.status.updated\",\n"; -echo " \"invoice\": {\n"; -echo " \"status\": \"void\",\n"; -echo " \"id\": \"FPBIV-250616-3UHJ\"\n"; -echo " }\n"; -echo " }\n"; -echo " \n"; -echo " For complete list of available invoice statuses, please refer to:\n"; -echo " https://docs.fasterpay.com/api#section-einvoice-api-statuses\n"; -echo " \n"; -echo " Status changes are automatically communicated via pingbacks\n"; -echo " to your configured pingback URL. The system will send status\n"; -echo " updates when invoices transition between different states\n"; -echo " during their lifecycle.\n"; - -echo "\nE-Invoice API examples completed!\n"; -echo "Use cases:\n"; -echo "• Automated billing and invoicing\n"; -echo "• Recurring subscription billing\n"; -echo "• Professional invoice generation\n"; -echo "• Payment tracking and reminders\n"; -echo "• Financial reporting and analytics\n"; -echo "• Multi-currency invoicing\n"; -echo "• Tax compliance and reporting\n"; -echo "• Customer payment portal integration\n"; "// Example 1: Create a new e-invoice with embedded components -echo "1. Creating a new e-invoice with embedded components\n"; -echo "----------------------------------------------------\n"; - -$invoiceData = array( - 'currency' => 'USD', - 'summary' => 'Website development project invoice', - 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => 'CT-250527-AZARCIJE', - 'template' => array( - 'name' => 'Project Template', - 'footer' => 'Thank you for your business!', - 'colors' => array( - 'primary' => '#2563eb', - 'secondary' => '#f8fafc' - ), - 'localized_address' => array( - 'address_line1' => '123 Business Ave', - 'locality' => 'San Francisco', - 'administrative_area' => 'CA', - 'postal_code' => '94105' - ), - 'country_code' => 'US' - ), - 'tax' => array( - 'name' => 'Sales Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% sales tax' - ), - 'discount' => array( - 'name' => 'Early Payment', - 'type' => 'flat', - 'value' => 50.0, - 'currency' => 'USD', - 'description' => '$50 early payment discount' - ), - 'items' => array( - array( - 'price' => 2500.00, - 'quantity' => 1, - 'product' => array( - 'sku' => 'WEB-DEV-PROJ', - 'type' => 'digital', - 'name' => 'Website Development', - 'description' => 'Complete website development project', - 'prices' => array( - array( - 'price' => 2500.00, - 'currency' => 'USD' - ) - ) - ), - 'tax' => array( - 'name' => 'Item Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% tax on this item' - ), - 'discount' => array( - 'name' => 'Item Discount', - 'type' => 'percentage', - 'value' => 5, - 'description' => '5% discount on this item' - ) - ) - ) -); - -try { - $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceData); - - if ($invoiceResponse->isSuccessful()) { - echo "✓ E-invoice with embedded components created successfully\n"; - $responseData = $invoiceResponse->getDecodeResponse(); - $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Invoice Number: " . $invoiceData['number'] . "\n"; - echo " Currency: " . $invoiceData['currency'] . "\n"; - echo " Items: " . count($invoiceData['items']) . "\n"; - echo " Template: " . $invoiceData['template']['name'] . "\n"; - } else { - echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 2: Create template with logo file (if you have a logo file) -echo "2. Creating invoice template with logo\n"; -echo "--------------------------------------\n"; - -$templateData = array( - 'name' => 'Professional Template with Logo', - 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', - 'colors' => array( - 'primary' => '#2563eb', - 'secondary' => '#f8fafc' - ), - 'localized_address' => array( - 'address_line1' => '123 Business Avenue', - 'locality' => 'San Francisco', - 'administrative_area' => 'CA', - 'postal_code' => '94105' - ), - 'country_code' => 'US' - // Note: For file upload, you would add: 'logo' => '@/path/to/logo.png' -); - -try { - $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); - - if ($templateResponse->isSuccessful()) { - echo "✓ Invoice template created successfully\n"; - $responseData = $templateResponse->getDecodeResponse(); - $templateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-' . time(); - echo " Template ID: " . $templateId . "\n"; - echo " Name: " . $templateData['name'] . "\n"; - echo " Primary Color: " . $templateData['colors']['primary'] . "\n"; - } else { - echo "✗ Error: " . $templateResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 3: Create tax -echo "3. Creating tax configuration\n"; -echo "-----------------------------\n"; - -$taxData = array( - 'name' => 'Sales Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% sales tax rate' -); - -try { - $taxResponse = $businessGateway->eInvoiceTaxService()->createTax($taxData); - - if ($taxResponse->isSuccessful()) { - echo "✓ Tax created successfully\n"; - $responseData = $taxResponse->getDecodeResponse(); - $taxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-' . time(); - echo " Tax ID: " . $taxId . "\n"; - echo " Name: " . $taxData['name'] . "\n"; - echo " Type: " . $taxData['type'] . "\n"; - echo " Rate: " . ($taxData['value'] * 100) . "%\n"; - } else { - echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 4: Create discount -echo "4. Creating discount offer\n"; -echo "--------------------------\n"; -$discountData = array( - 'name' => 'Early Bird Discount', - 'type' => 'flat', - 'value' => 50.0, - 'currency' => 'USD', - 'description' => '$50 discount for early payment' -); + // Example 4: List invoices with filters + echo "4. Listing invoices with filters\n"; + echo "--------------------------------\n"; -try { - $discountResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($discountData); + $filters = [ + 'limit' => 10, + 'offset' => 0, + 'status' => 'draft' + ]; - if ($discountResponse->isSuccessful()) { - echo "✓ Discount created successfully\n"; - $responseData = $discountResponse->getDecodeResponse(); - $discountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-' . time(); - echo " Discount ID: " . $discountId . "\n"; - echo " Name: " . $discountData['name'] . "\n"; - echo " Value: $" . $discountData['value'] . " " . $discountData['currency'] . "\n"; - } else { - echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} + $response = $businessGateway->invoiceService()->listInvoices($filters); -echo "\n"; + if ($response->isSuccessful()) { + echo "✓ Invoices listed successfully!\n"; + $data = $response->getDecodeResponse(); + $invoices = $data['data']['data']; + echo " Found " . count($invoices) . " draft invoices\n"; -// Example 5: Create product with image (if you have an image file) -echo "5. Creating product with image\n"; -echo "------------------------------\n"; - -$productData = array( - 'sku' => 'WEB-DEV-001', - 'type' => 'digital', - 'name' => 'Website Development Package', - 'description' => 'Complete website development with modern responsive design', - 'prices' => array( - array( - 'price' => 2500.00, - 'currency' => 'USD' - ) - ) - // Note: For file upload, you would add: 'image' => '@/path/to/product-image.jpg' -); - -try { - $productResponse = $businessGateway->eInvoiceProductService()->createProduct($productData); - - if ($productResponse->isSuccessful()) { - echo "✓ Product created successfully\n"; - $responseData = $productResponse->getDecodeResponse(); - $productId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-' . time(); - echo " Product ID: " . $productId . "\n"; - echo " SKU: " . $productData['sku'] . "\n"; - echo " Name: " . $productData['name'] . "\n"; - echo " Type: " . $productData['type'] . "\n"; - } else { - echo "✗ Error: " . $productResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 6: Update invoice using POST with _method=PUT -echo "6. Updating invoice\n"; -echo "-------------------\n"; - -$invoiceId = isset($invoiceId) ? $invoiceId : 'FPBIV-' . time(); -$updateData = array( - 'summary' => 'Updated website development project invoice', - 'template' => array( - 'footer' => 'Updated footer - Thank you for choosing our services!' - ) -); - -try { - $updateResponse = $businessGateway->eInvoiceService()->updateInvoice($invoiceId, $updateData); - - if ($updateResponse->isSuccessful()) { - echo "✓ Invoice updated successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Updated summary and template footer\n"; - } else { - echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 7: Send invoice to customer -echo "7. Sending invoice to customer\n"; -echo "------------------------------\n"; - -$sendParams = array( - 'method' => 'email', - 'email' => 'customer@example.com', - 'subject' => 'Invoice ' . (isset($invoiceData['number']) ? $invoiceData['number'] : 'INV-001') . ' from Your Company', - 'message' => 'Dear Customer, please find attached your invoice. Payment is due within 30 days.', - 'copy_sender' => true, - 'attach_pdf' => true -); - -try { - $sendResponse = $businessGateway->eInvoiceService()->sendInvoice($invoiceId, $sendParams); - - if ($sendResponse->isSuccessful()) { - echo "✓ Invoice sent successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Sent to: " . $sendParams['email'] . "\n"; - echo " Method: " . $sendParams['method'] . "\n"; - echo " PDF attached: " . ($sendParams['attach_pdf'] ? 'Yes' : 'No') . "\n"; + foreach (array_slice($invoices, 0, 3) as $invoice) { + echo " - " . $invoice['id'] . " (" . $invoice['status'] . ")\n"; + } + echo "\n"; } else { - echo "✗ Error: " . $sendResponse->getErrors()->getMessage() . "\n"; + echo "✗ Failed to list invoices\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; -// Example 8: Download invoice PDF (file response) -echo "8. Downloading invoice PDF\n"; -echo "--------------------------\n"; + // Example 5: Update invoice details + echo "5. Updating invoice details\n"; + echo "---------------------------\n"; -$downloadOptions = array( - 'format' => 'pdf', - 'template' => 'professional', - 'include_payments' => true -); + if (isset($invoiceId)) { + $updateData = [ + 'summary' => 'Updated website development project invoice', + 'template' => [ + 'footer' => 'Updated footer - Thank you for choosing our services!' + ] + ]; -try { - // downloadInvoicePdf returns raw file data, not GeneralResponse - $downloadResponse = $businessGateway->eInvoiceService()->downloadInvoicePdf($invoiceId, $downloadOptions); + $response = $businessGateway->invoiceService()->updateInvoice($invoiceId, $updateData); - if ($downloadResponse['httpCode'] == 200) { - echo "✓ Invoice PDF downloaded successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Content-Length: " . strlen($downloadResponse['response']) . " bytes\n"; - echo " Content-Type: PDF\n"; - - // In a real application, you would save this to a file: - // $filename = 'invoice_' . $invoiceId . '.pdf'; - // file_put_contents($filename, $downloadResponse['response']); - // echo " Saved as: " . $filename . "\n"; - - echo " (File content received - would be saved as PDF in real application)\n"; - } else { - echo "✗ Error downloading PDF: HTTP " . $downloadResponse['httpCode'] . "\n"; - if (!empty($downloadResponse['response'])) { - // Try to decode error response - $errorData = json_decode($downloadResponse['response'], true); - if ($errorData && isset($errorData['message'])) { - echo " Error message: " . $errorData['message'] . "\n"; - } + if ($response->isSuccessful()) { + echo "✓ Invoice updated successfully!\n"; + echo " Updated summary and template footer\n\n"; + } else { + echo "✗ Failed to update invoice\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 9: Get invoice details -echo "9. Getting invoice details\n"; -echo "--------------------------\n"; - -try { - $detailsResponse = $businessGateway->eInvoiceService()->getInvoice($invoiceId); - if ($detailsResponse->isSuccessful()) { - echo "✓ Invoice details retrieved successfully\n"; - $details = $detailsResponse->getDecodeResponse(); - - if (isset($details['data'])) { - $invoice = $details['data']; - echo " Invoice ID: " . (isset($invoice['id']) ? $invoice['id'] : $invoiceId) . "\n"; - echo " Status: " . (isset($invoice['status']) ? $invoice['status'] : 'N/A') . "\n"; - echo " Currency: " . (isset($invoice['currency']) ? $invoice['currency'] : 'N/A') . "\n"; - echo " Summary: " . (isset($invoice['summary']) ? $invoice['summary'] : 'N/A') . "\n"; - echo " Created: " . (isset($invoice['created_at']) ? $invoice['created_at'] : 'N/A') . "\n"; + // Example 6: Update invoice status + echo "6. Updating invoice status\n"; + echo "--------------------------\n"; + + if (isset($invoiceId)) { + $statusParams = [ + 'status' => 'sent', + 'notes' => 'Invoice sent to customer via email' + ]; + + $response = $businessGateway->invoiceService()->updateInvoiceStatus($invoiceId, $statusParams); + + if ($response->isSuccessful()) { + echo "✓ Invoice status updated successfully!\n"; + echo " New status: " . $statusParams['status'] . "\n"; + echo " Notes: " . $statusParams['notes'] . "\n\n"; + } else { + echo "✗ Failed to update invoice status\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } - } else { - echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; -// Example 8: List invoices -echo "8. Listing invoices\n"; -echo "-------------------\n"; + // Example 7: Preview invoice HTML + echo "7. Previewing invoice HTML\n"; + echo "--------------------------\n"; -$filters = array( - 'limit' => 20, - 'offset' => 0 -); + if (isset($invoiceId)) { + $response = $businessGateway->invoiceService()->previewInvoice($invoiceId); -try { - $listResponse = $businessGateway->eInvoiceService()->listInvoices($filters); - - if ($listResponse->isSuccessful()) { - echo "✓ Invoice list retrieved successfully\n"; - echo " Limit: 20 invoices\n"; - - $listData = $listResponse->getDecodeResponse(); - if (isset($listData['data']) && is_array($listData['data'])) { - echo " Found " . count($listData['data']) . " invoices\n"; - - // Display first few invoices - $invoices = array_slice($listData['data'], 0, 3); - foreach ($invoices as $invoice) { - $id = isset($invoice['id']) ? $invoice['id'] : 'Unknown'; - $status = isset($invoice['status']) ? $invoice['status'] : 'Unknown'; - $currency = isset($invoice['currency']) ? $invoice['currency'] : 'Unknown'; - echo " - " . $id . " (Status: " . $status . ", Currency: " . $currency . ")\n"; - } - - if (count($listData['data']) > 3) { - echo " ... and " . (count($listData['data']) - 3) . " more\n"; - } + if ($response->isSuccessful()) { + echo "✓ Invoice preview generated successfully!\n"; + $htmlContent = $response->getRaw(); + echo " HTML content length: " . strlen($htmlContent) . " characters\n\n"; + } else { + echo "✗ Failed to generate invoice preview\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } - } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 9: Delete invoice -echo "9. Deleting invoice\n"; -echo "-------------------\n"; - -$invoiceToDelete = 'FPBIV-DELETE-' . time(); // Use a test invoice ID - -try { - $deleteResponse = $businessGateway->eInvoiceService()->deleteInvoice($invoiceToDelete); - - if ($deleteResponse->isSuccessful()) { - echo "✓ Invoice deleted successfully\n"; - echo " Deleted Invoice ID: " . $invoiceToDelete . "\n"; - } else { - echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 10: Handle invoice status via pingbacks (documentation example) -echo "10. Invoice status handling via pingbacks\n"; -echo "-----------------------------------------\n"; - -echo "✓ Invoice status changes are handled via pingbacks\n"; -echo " Pingback example from API documentation:\n"; -echo " {\n"; -echo " \"event\": \"invoice.status.updated\",\n"; -echo " \"invoice\": {\n"; -echo " \"status\": \"void\",\n"; -echo " \"id\": \"FPBIV-250616-3UHJ\"\n"; -echo " }\n"; -echo " }\n"; -echo " \n"; -echo " Available invoice statuses include:\n"; -echo " - draft: Invoice is in draft status\n"; -echo " - sent: Invoice has been sent to customer\n"; -echo " - paid: Invoice has been paid\n"; -echo " - void: Invoice has been voided/cancelled\n"; -echo " - overdue: Invoice payment is overdue\n"; -echo " \n"; -echo " Status changes are automatically communicated via pingbacks\n"; -echo " to your configured pingback URL.\n"; '', - 'privateKey' => '', - 'isTest' => 1, -)); -echo "FasterPay E-Invoice API Examples\n"; -echo "=================================\n\n"; - -// Example 1: Create a new e-invoice -echo "1. Creating a new e-invoice\n"; -echo "---------------------------\n"; + // Example 8: Download invoice PDF + echo "8. Downloading invoice PDF\n"; + echo "--------------------------\n"; -$invoiceData = array( - 'currency' => 'USD', - 'summary' => 'Website development project invoice', - 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => 'CT-250527-AZARCIJE', - 'items' => array( - array( - 'price' => 2500.00, - 'quantity' => 1, - 'name' => 'Website Development Services', - 'description' => 'Complete website development with responsive design' - ), - array( - 'price' => 99.99, - 'quantity' => 12, - 'name' => 'Monthly Hosting Package', - 'description' => 'Premium hosting service for 12 months' - ) - ) -); - -try { - $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceData); + if (isset($invoiceId)) { + $response = $businessGateway->invoiceService()->downloadInvoicePdf($invoiceId); - if ($invoiceResponse->isSuccessful()) { - echo "✓ E-invoice created successfully\n"; - $responseData = $invoiceResponse->getDecodeResponse(); - $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Invoice Number: " . $invoiceData['number'] . "\n"; - echo " Currency: " . $invoiceData['currency'] . "\n"; - echo " Items: " . count($invoiceData['items']) . "\n"; - } else { - echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} + if ($response->isSuccessful()) { + echo "✓ Invoice PDF downloaded successfully!\n"; + $pdfContent = $response->getRaw(); + echo " PDF size: " . strlen($pdfContent) . " bytes\n"; -echo "\n"; - -// Example 2: Create template -echo "2. Creating invoice template\n"; -echo "----------------------------\n"; - -$templateData = array( - 'name' => 'Professional Template', - 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', - 'colors' => array( - 'primary' => '#2563eb', - 'secondary' => '#f8fafc' - ), - 'localized_address' => array( - 'address_line1' => '123 Business Avenue', - 'locality' => 'San Francisco', - 'administrative_area' => 'CA', - 'postal_code' => '94105' - ), - 'country_code' => 'US' -); - -try { - $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); - - if ($templateResponse->isSuccessful()) { - echo "✓ Invoice template created successfully\n"; - $responseData = $templateResponse->getDecodeResponse(); - $templateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-' . time(); - echo " Template ID: " . $templateId . "\n"; - echo " Name: " . $templateData['name'] . "\n"; - echo " Primary Color: " . $templateData['colors']['primary'] . "\n"; - } else { - echo "✗ Error: " . $templateResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 3: Create tax -echo "3. Creating tax configuration\n"; -echo "-----------------------------\n"; - -$taxData = array( - 'name' => 'Sales Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% sales tax rate' -); - -try { - $taxResponse = $businessGateway->eInvoiceTaxService()->createTax($taxData); - - if ($taxResponse->isSuccessful()) { - echo "✓ Tax created successfully\n"; - $responseData = $taxResponse->getDecodeResponse(); - $taxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-' . time(); - echo " Tax ID: " . $taxId . "\n"; - echo " Name: " . $taxData['name'] . "\n"; - echo " Type: " . $taxData['type'] . "\n"; - echo " Rate: " . ($taxData['value'] * 100) . "%\n"; - } else { - echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 4: Create discount -echo "4. Creating discount offer\n"; -echo "--------------------------\n"; - -$discountData = array( - 'name' => 'Early Bird Discount', - 'type' => 'flat', - 'value' => 50.0, - 'currency' => 'USD', - 'description' => '$50 discount for early payment' -); - -try { - $discountResponse = $businessGateway->eInvoiceDiscountService()->createDiscount($discountData); - - if ($discountResponse->isSuccessful()) { - echo "✓ Discount created successfully\n"; - $responseData = $discountResponse->getDecodeResponse(); - $discountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-' . time(); - echo " Discount ID: " . $discountId . "\n"; - echo " Name: " . $discountData['name'] . "\n"; - echo " Value: $" . $discountData['value'] . " " . $discountData['currency'] . "\n"; - } else { - echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 5: Create product -echo "5. Creating product\n"; -echo "-------------------\n"; - -$productData = array( - 'sku' => 'WEB-DEV-001', - 'type' => 'digital', - 'name' => 'Website Development Package', - 'description' => 'Complete website development with modern responsive design', - 'prices' => array( - array( - 'price' => 2500.00, - 'currency' => 'USD' - ) - ) -); - -try { - $productResponse = $businessGateway->eInvoiceProductService()->createProduct($productData); - - if ($productResponse->isSuccessful()) { - echo "✓ Product created successfully\n"; - $responseData = $productResponse->getDecodeResponse(); - $productId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-' . time(); - echo " Product ID: " . $productId . "\n"; - echo " SKU: " . $productData['sku'] . "\n"; - echo " Name: " . $productData['name'] . "\n"; - echo " Type: " . $productData['type'] . "\n"; - } else { - echo "✗ Error: " . $productResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 6: Send invoice -echo "6. Sending invoice to customer\n"; -echo "------------------------------\n"; - -$invoiceId = isset($invoiceId) ? $invoiceId : 'FPBIV-' . time(); -$sendParams = array( - 'method' => 'email', - 'email' => 'customer@example.com', - 'subject' => 'Invoice ' . (isset($invoiceData['number']) ? $invoiceData['number'] : 'INV-001') . ' from Your Company', - 'message' => 'Dear Customer, please find attached your invoice. Payment is due within 30 days.', - 'copy_sender' => true -); - -try { - $sendResponse = $businessGateway->eInvoiceService()->sendInvoice($invoiceId, $sendParams); - - if ($sendResponse->isSuccessful()) { - echo "✓ Invoice sent successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Sent to: " . $sendParams['email'] . "\n"; - echo " Method: " . $sendParams['method'] . "\n"; - } else { - echo "✗ Error: " . $sendResponse->getErrors()->getMessage() . "\n"; + // Optionally save to file + // file_put_contents('invoice_' . $invoiceId . '.pdf', $pdfContent); + echo "\n"; + } else { + echo "✗ Failed to download invoice PDF\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; + } } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} -echo "\n"; - -// Example 7: Mark invoice as paid -echo "7. Marking invoice as paid\n"; -echo "--------------------------\n"; - -$paymentData = array( - 'amount' => 2599.99, - 'payment_date' => date('Y-m-d'), - 'payment_method' => 'bank_transfer', - 'reference' => 'TXN-' . time(), - 'notes' => 'Payment received via bank transfer' -); - -try { - $paidResponse = $businessGateway->eInvoiceService()->markAsPaid($invoiceId, $paymentData); - - if ($paidResponse->isSuccessful()) { - echo "✓ Invoice marked as paid successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Amount: $" . number_format($paymentData['amount'], 2) . "\n"; - echo " Payment Date: " . $paymentData['payment_date'] . "\n"; - echo " Method: " . $paymentData['payment_method'] . "\n"; - } else { - echo "✗ Error: " . $paidResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} + // Example 9: Send invoice to customer + echo "9. Sending invoice to customer\n"; + echo "------------------------------\n"; -echo "\n"; + if (isset($invoiceId)) { + // Send test email first + $response = $businessGateway->invoiceService()->sendInvoice($invoiceId, ['test' => true]); -// Example 8: List invoices -echo "8. Listing invoices\n"; -echo "-------------------\n"; + if ($response->isSuccessful()) { + echo "✓ Test invoice email sent successfully!\n"; -$filters = array( - 'limit' => 20, - 'offset' => 0 -); + // Send actual invoice + $response = $businessGateway->invoiceService()->sendInvoice($invoiceId); -try { - $listResponse = $businessGateway->eInvoiceService()->listInvoices($filters); - - if ($listResponse->isSuccessful()) { - echo "✓ Invoice list retrieved successfully\n"; - echo " Limit: 20 invoices\n"; - - $listData = $listResponse->getDecodeResponse(); - if (isset($listData['data']) && is_array($listData['data'])) { - echo " Found " . count($listData['data']) . " invoices\n"; - - // Display first few invoices - $invoices = array_slice($listData['data'], 0, 3); - foreach ($invoices as $invoice) { - $id = isset($invoice['id']) ? $invoice['id'] : 'Unknown'; - $status = isset($invoice['status']) ? $invoice['status'] : 'Unknown'; - $currency = isset($invoice['currency']) ? $invoice['currency'] : 'Unknown'; - echo " - " . $id . " (Status: " . $status . ", Currency: " . $currency . ")\n"; - } - - if (count($listData['data']) > 3) { - echo " ... and " . (count($listData['data']) - 3) . " more\n"; + if ($response->isSuccessful()) { + echo "✓ Invoice sent to customer successfully!\n\n"; + } else { + echo "✗ Failed to send invoice to customer\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } + } else { + echo "✗ Failed to send test invoice\n"; + echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; } - } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; -// Example 9: Get invoice status -echo "9. Getting invoice status\n"; -echo "-------------------------\n"; + // Example 10: Delete operations (cleanup) + echo "10. Cleanup operations\n"; + echo "----------------------\n"; -try { - $statusResponse = $businessGateway->eInvoiceService()->getInvoiceStatus($invoiceId); + // Delete test invoice + $testInvoiceId = 'FPBIV-DELETE-' . time(); + $response = $businessGateway->invoiceService()->deleteInvoice($testInvoiceId); - if ($statusResponse->isSuccessful()) { - echo "✓ Invoice status retrieved successfully\n"; - $statusData = $statusResponse->getDecodeResponse(); - echo " Invoice ID: " . $invoiceId . "\n"; - - if (isset($statusData['data'])) { - $status = $statusData['data']; - echo " Status: " . (isset($status['status']) ? $status['status'] : 'N/A') . "\n"; - echo " Last updated: " . (isset($status['updated_at']) ? $status['updated_at'] : date('Y-m-d H:i:s')) . "\n"; - } + if ($response->isSuccessful()) { + echo "✓ Test invoice deleted successfully\n"; } else { - echo "✗ Error: " . $statusResponse->getErrors()->getMessage() . "\n"; + echo "✓ Expected error for non-existent invoice (cleanup test)\n"; } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; -// Example 10: Cancel invoice -echo "10. Cancelling invoice\n"; -echo "----------------------\n"; + echo "\n"; -$cancelParams = array( - 'reason' => 'Customer requested cancellation' -); - -try { - $cancelResponse = $businessGateway->eInvoiceService()->cancelInvoice($invoiceId, $cancelParams); - - if ($cancelResponse->isSuccessful()) { - echo "✓ Invoice cancelled successfully\n"; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Reason: " . $cancelParams['reason'] . "\n"; - } else { - echo "✗ Error: " . $cancelResponse->getErrors()->getMessage() . "\n"; - } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "✗ An error occurred: " . $e->getMessage() . "\n"; + echo " Stack trace:\n" . $e->getTraceAsString() . "\n"; } -echo "\nE-Invoice API examples completed!\n"; -echo "Use cases:\n"; -echo "• Automated billing and invoicing\n"; +echo "\nE-Invoice API Examples Completed!\n"; +echo "==================================\n\n"; + +echo "Key Features Demonstrated:\n"; +echo "- Create invoices with embedded components (templates, products, taxes, discounts)\n"; +echo "- Create invoices using existing component IDs\n"; +echo "- Retrieve and list invoices with filtering\n"; +echo "- Update invoice details and status\n"; +echo "- Preview invoices and download PDFs\n"; +echo "- Send invoices to customers\n"; +echo "- Manage templates, products, taxes, and discounts\n"; +echo "- Handle webhook notifications\n"; +echo "- Comprehensive error handling\n"; +echo "- File upload support for multipart requests\n\n"; + +echo "Use Cases:\n"; +echo "• Automated billing and invoicing systems\n"; echo "• Recurring subscription billing\n"; echo "• Professional invoice generation\n"; echo "• Payment tracking and reminders\n"; echo "• Financial reporting and analytics\n"; echo "• Multi-currency invoicing\n"; echo "• Tax compliance and reporting\n"; -echo "• Customer payment portal integration\n"; \ No newline at end of file +echo "• Customer payment portal integration\n"; +echo "• E-commerce order invoicing\n"; +echo "• Service-based business billing\n\n"; + +echo "Best Practices:\n"; +echo "- Validate only route parameters (IDs) - API handles all other parameter validation\n"; +echo "- Use BusinessGateway service methods for consistent architecture\n"; +echo "- Handle responses using isSuccessful(), getDecodeResponse(), and getErrors()\n"; +echo "- Use appropriate HTTP methods via HttpClient (post, get, put, delete)\n"; +echo "- Implement proper error handling and logging\n"; +echo "- Use webhook handlers for real-time status updates\n"; +echo "- Follow the documented invoice status lifecycle\n"; +echo "- Store component IDs for reuse and reference\n"; +echo "- Use test mode during development and integration\n"; +echo "- Implement retry logic for transient failures\n\n"; + +echo "Configuration Notes:\n"; +echo "- Set publicKey and privateKey to your actual FasterPay keys\n"; +echo "- Set isTest to 0 for production environment\n"; +echo "- Ensure contact_id references exist before creating invoices\n"; +echo "- Configure webhook URLs in your FasterPay dashboard\n"; +echo "- Test all operations in sandbox before going live\n"; \ No newline at end of file diff --git a/code-samples/business/e-invoice/product.php b/code-samples/business/e-invoice/product.php index 5360d42..c4d20fb 100644 --- a/code-samples/business/e-invoice/product.php +++ b/code-samples/business/e-invoice/product.php @@ -5,21 +5,20 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1, ]); -echo "FasterPay E-Invoice Product API Examples\n"; -echo "=========================================\n\n"; +echo "FasterPay Invoice Product API Examples\n"; +echo "=======================================\n\n"; -// Example 1: Create a digital product with multiple currencies -echo "1. Creating a digital product with multiple currencies\n"; -echo "------------------------------------------------------\n"; +// Example 1: Create a new product +echo "1. Creating a new product\n"; +echo "-------------------------\n"; -$digitalProductData = [ - 'name' => 'Website Development Package', - 'sku' => 'WEB-DEV-001', +$productData = [ + 'name' => 'Professional Website Package', + 'sku' => 'WEB-PRO-001', 'type' => 'digital', - 'description' => 'Complete website development with modern responsive design, SEO optimization, and content management system.', + 'description' => 'Complete professional website package with responsive design and SEO optimization', 'prices' => [ [ 'price' => 2500.00, @@ -28,29 +27,24 @@ [ 'price' => 2100.00, 'currency' => 'EUR' - ], - [ - 'price' => 1850.00, - 'currency' => 'GBP' ] ] ]; try { - $digitalProductResponse = $businessGateway->eInvoiceProductService()->createProduct($digitalProductData); - - if ($digitalProductResponse->isSuccessful()) { - echo "Digital product created successfully\n"; - $responseData = $digitalProductResponse->getDecodeResponse(); - $digitalProductId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-DIGITAL-' . time(); - echo " Product ID: " . $digitalProductId . "\n"; - echo " SKU: " . $digitalProductData['sku'] . "\n"; - echo " Name: " . $digitalProductData['name'] . "\n"; - echo " Type: " . $digitalProductData['type'] . "\n"; - echo " Prices: USD 2500.00 / EUR 2100.00 / GBP 1850.00\n"; - echo " Image URL: " . (isset($responseData['data']['image_url']) ? $responseData['data']['image_url'] : 'No image uploaded') . "\n"; + $productResponse = $businessGateway->invoiceProductService()->createProduct($productData); + + if ($productResponse->isSuccessful()) { + echo "Product created successfully\n"; + $responseData = $productResponse->getDecodeResponse(); + $productId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-' . time(); + echo " Product ID: " . $productId . "\n"; + echo " SKU: " . $productData['sku'] . "\n"; + echo " Name: " . $productData['name'] . "\n"; + echo " Type: " . $productData['type'] . "\n"; + echo " Prices: " . count($productData['prices']) . " currencies\n"; } else { - echo "Error: " . $digitalProductResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $productResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -58,43 +52,43 @@ echo "\n"; -// Example 2: Create a physical product with image upload (multipart) -echo "2. Creating a physical product with image upload\n"; -echo "------------------------------------------------\n"; +// Example 2: Create product with image +echo "2. Creating product with image\n"; +echo "------------------------------\n"; -$physicalProductData = [ - 'name' => 'Professional Laptop 15 inch', - 'sku' => 'LAPTOP-PRO-15', - 'type' => 'physical', - 'description' => 'High-performance laptop with 16GB RAM, 512GB SSD, and professional graphics card. Perfect for developers and designers.', - 'image' => '/path/to/laptop-image.jpg', // This will trigger multipart upload +$productWithImageData = [ + 'name' => 'Premium Software License', + 'sku' => 'SW-PREM-001', + 'type' => 'digital', + 'description' => 'Premium software license with full features and 1-year support', 'prices' => [ [ - 'price' => 1899.99, + 'price' => 299.99, 'currency' => 'USD' - ], - [ - 'price' => 1649.99, - 'currency' => 'EUR' ] - ] + ], + 'image' => '/path/to/product-image.jpg' // File path provided directly in params ]; try { - $physicalProductResponse = $businessGateway->eInvoiceProductService()->createProduct($physicalProductData); - - if ($physicalProductResponse->isSuccessful()) { - echo "Physical product created successfully\n"; - $responseData = $physicalProductResponse->getDecodeResponse(); - $physicalProductId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-PHYSICAL-' . time(); - echo " Product ID: " . $physicalProductId . "\n"; - echo " SKU: " . $physicalProductData['sku'] . "\n"; - echo " Name: " . $physicalProductData['name'] . "\n"; - echo " Type: " . $physicalProductData['type'] . "\n"; - echo " Prices: USD 1899.99 / EUR 1649.99\n"; - echo " Image URL: " . (isset($responseData['data']['image_url']) ? $responseData['data']['image_url'] : 'No image uploaded') . "\n"; + // Note: In real implementation, provide actual image file path in params['image'] + // The service automatically detects file fields and uses multipart upload + + // For demo purposes, create without image + $demoData = $productWithImageData; + unset($demoData['image']); // Remove for demo + $imageResponse = $businessGateway->invoiceProductService()->createProduct($demoData); + + if ($imageResponse->isSuccessful()) { + echo "Product with image created successfully\n"; + $responseData = $imageResponse->getDecodeResponse(); + $imageProductId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-IMG-' . time(); + echo " Product ID: " . $imageProductId . "\n"; + echo " Name: " . $productWithImageData['name'] . "\n"; + echo " Image: File would be uploaded automatically if 'image' field contains file path\n"; + echo " Usage: \$params['image'] = '/path/to/image.jpg'\n"; } else { - echo "Error: " . $physicalProductResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $imageResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -106,34 +100,30 @@ echo "3. Getting product details\n"; echo "--------------------------\n"; -$productIdToGet = isset($digitalProductId) ? $digitalProductId : 'PD-250528-L5CC'; +$productId = isset($productId) ? $productId : 'PD-' . time(); try { - $productDetailsResponse = $businessGateway->eInvoiceProductService()->getProduct($productIdToGet); - - if ($productDetailsResponse->isSuccessful()) { - echo "Product details retrieved successfully\n"; - $productData = $productDetailsResponse->getDecodeResponse(); - - if (isset($productData['data'])) { - $product = $productData['data']; - echo " Product ID: " . (isset($product['id']) ? $product['id'] : 'N/A') . "\n"; - echo " SKU: " . (isset($product['sku']) ? $product['sku'] : 'N/A') . "\n"; - echo " Name: " . (isset($product['name']) ? $product['name'] : 'N/A') . "\n"; - echo " Type: " . (isset($product['type']) ? $product['type'] : 'N/A') . "\n"; - echo " Description: " . (isset($product['description']) ? substr($product['description'], 0, 100) . '...' : 'N/A') . "\n"; - - if (isset($product['prices']) && is_array($product['prices'])) { - echo " Prices:\n"; - foreach ($product['prices'] as $price) { - $priceAmount = isset($price['price']) ? $price['price'] : '0.00'; - $currency = isset($price['currency']) ? $price['currency'] : 'N/A'; - echo " - " . $priceAmount . " " . $currency . "\n"; - } + $detailsResponse = $businessGateway->invoiceProductService()->getProduct($productId); + + if ($detailsResponse->isSuccessful()) { + echo "Product details retrieved\n"; + $details = $detailsResponse->getDecodeResponse(); + $product = isset($details['data']) ? $details['data'] : []; + + echo " ID: " . (isset($product['id']) ? $product['id'] : $productId) . "\n"; + echo " Name: " . (isset($product['name']) ? $product['name'] : 'N/A') . "\n"; + echo " SKU: " . (isset($product['sku']) ? $product['sku'] : 'N/A') . "\n"; + echo " Type: " . (isset($product['type']) ? $product['type'] : 'N/A') . "\n"; + echo " Description: " . substr(isset($product['description']) ? $product['description'] : 'N/A', 0, 50) . "...\n"; + + if (isset($product['prices']) && is_array($product['prices'])) { + echo " Prices:\n"; + foreach ($product['prices'] as $price) { + echo " - " . (isset($price['currency']) ? $price['currency'] : 'N/A') . ": " . (isset($price['price']) ? $price['price'] : '0.00') . "\n"; } } } else { - echo "Error: " . $productDetailsResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -141,42 +131,32 @@ echo "\n"; -// Example 4: Update product with image upload (multipart) -echo "4. Updating product with image upload\n"; -echo "-------------------------------------\n"; - -$productIdToUpdate = isset($physicalProductId) ? $physicalProductId : 'PD-UPDATE-' . time(); +// Example 4: Update product +echo "4. Updating product\n"; +echo "-------------------\n"; $updateData = [ - 'name' => 'Professional Laptop 15 inch - Updated Edition', - 'description' => 'Updated high-performance laptop with enhanced features: 32GB RAM, 1TB SSD, and latest graphics card.', - 'image' => '/path/to/updated-laptop-image.jpg', // This will trigger multipart upload + 'name' => 'Updated Professional Website Package', + 'description' => 'Enhanced professional website package with advanced SEO optimization and mobile app integration', 'prices' => [ [ - 'price' => 2199.99, + 'price' => 2750.00, 'currency' => 'USD' ], [ - 'price' => 1899.99, + 'price' => 2300.00, 'currency' => 'EUR' - ], - [ - 'price' => 1699.99, - 'currency' => 'GBP' ] ] ]; try { - $updateResponse = $businessGateway->eInvoiceProductService()->updateProduct($productIdToUpdate, $updateData); + $updateResponse = $businessGateway->invoiceProductService()->updateProduct($productId, $updateData); if ($updateResponse->isSuccessful()) { echo "Product updated successfully\n"; - $responseData = $updateResponse->getDecodeResponse(); - echo " Product ID: " . $productIdToUpdate . "\n"; - echo " Updated Name: " . $updateData['name'] . "\n"; - echo " Updated Prices: USD 2199.99 / EUR 1899.99 / GBP 1699.99\n"; - echo " Image URL: " . (isset($responseData['data']['image_url']) ? $responseData['data']['image_url'] : 'No image uploaded') . "\n"; + echo " Updated name and description\n"; + echo " Updated prices for USD and EUR\n"; } else { echo "Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } @@ -186,40 +166,30 @@ echo "\n"; -// Example 5: List products with filters -echo "5. Listing products with filters\n"; -echo "--------------------------------\n"; +// Example 5: List all products +echo "5. Listing all products\n"; +echo "-----------------------\n"; -$filters = [ - 'limit' => 20, - 'offset' => 0, - 'type' => 'digital' +$listFilters = [ + 'page' => 1, + 'per_page' => 10 ]; try { - $listResponse = $businessGateway->eInvoiceProductService()->listProducts($filters); + $listResponse = $businessGateway->invoiceProductService()->listProducts($listFilters); if ($listResponse->isSuccessful()) { - echo "Product list retrieved successfully\n"; + echo "Products list retrieved\n"; $listData = $listResponse->getDecodeResponse(); - - if (isset($listData['data']) && is_array($listData['data'])) { - echo " Found " . count($listData['data']) . " digital products\n"; - - // Display first few products - $products = array_slice($listData['data'], 0, 3); - foreach ($products as $product) { - $id = isset($product['id']) ? $product['id'] : 'Unknown'; - $name = isset($product['name']) ? $product['name'] : 'Unnamed'; - $sku = isset($product['sku']) ? $product['sku'] : 'No SKU'; - $type = isset($product['type']) ? $product['type'] : 'Unknown'; - - echo " - " . $name . " (" . $id . ", SKU: " . $sku . ", Type: " . $type . ")\n"; - } - - if (count($listData['data']) > 3) { - echo " ... and " . (count($listData['data']) - 3) . " more\n"; - } + $products = isset($listData['data']['data']) ? $listData['data']['data'] : []; + + echo " Found " . count($products) . " products\n"; + foreach ($products as $product) { + $id = isset($product['id']) ? $product['id'] : 'Unknown'; + $name = isset($product['name']) ? $product['name'] : 'Unnamed'; + $sku = isset($product['sku']) ? $product['sku'] : 'No SKU'; + $type = isset($product['type']) ? $product['type'] : 'unknown'; + echo " - $name ($sku) - Type: $type - ID: $id\n"; } } else { echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; @@ -230,18 +200,66 @@ echo "\n"; -// Example 6: Delete product price -echo "6. Deleting product price\n"; -echo "-------------------------\n"; +// Example 6: Create multiple products (bulk operation) +echo "6. Creating multiple products (bulk operation)\n"; +echo "----------------------------------------------\n"; -$productIdForPriceDeletion = isset($digitalProductId) ? $digitalProductId : 'PD-PRICE-DELETE-' . time(); -$currencyToDelete = 'GBP'; +$bulkProducts = [ + [ + 'name' => 'Basic Hosting Plan', + 'sku' => 'HOST-BASIC-001', + 'type' => 'digital', + 'description' => 'Basic web hosting plan with 10GB storage', + 'prices' => [['price' => 9.99, 'currency' => 'USD']] + ], + [ + 'name' => 'Premium Hosting Plan', + 'sku' => 'HOST-PREM-001', + 'type' => 'digital', + 'description' => 'Premium web hosting plan with 100GB storage and SSL', + 'prices' => [['price' => 29.99, 'currency' => 'USD']] + ], + [ + 'name' => 'Physical Marketing Kit', + 'sku' => 'MKT-KIT-001', + 'type' => 'physical', + 'description' => 'Complete marketing kit with brochures and business cards', + 'prices' => [['price' => 149.99, 'currency' => 'USD']] + ] +]; + +foreach ($bulkProducts as $productData) { + try { + $response = $businessGateway->invoiceProductService()->createProduct($productData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $id = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-BULK-' . time(); + $price = $productData['prices'][0]['price']; + $currency = $productData['prices'][0]['currency']; + echo " Created: {$productData['name']} (SKU: {$productData['sku']}, Price: $price $currency)\n"; + } else { + echo " Error creating {$productData['name']}: " . $response->getErrors()->getMessage() . "\n"; + } + } catch (FasterPay\Exception $e) { + echo " Exception creating {$productData['name']}: " . $e->getMessage() . "\n"; + } +} + +echo "\n"; + +// Example 7: Delete price from product +echo "7. Deleting price from product\n"; +echo "------------------------------\n"; + +$productIdForPriceDeletion = isset($productId) ? $productId : 'PD-' . time(); +$currencyToDelete = 'EUR'; try { - $deletePriceResponse = $businessGateway->eInvoiceProductService()->deleteProductPrice($productIdForPriceDeletion, $currencyToDelete); + $deletePriceResponse = $businessGateway->invoiceProductService()->deleteProductPrice($productIdForPriceDeletion, $currencyToDelete); if ($deletePriceResponse->isSuccessful()) { - echo "Product price deleted successfully\n"; + echo "Price deleted successfully\n"; echo " Product ID: " . $productIdForPriceDeletion . "\n"; echo " Deleted Currency: " . $currencyToDelete . "\n"; } else { @@ -253,8 +271,8 @@ echo "\n"; -// Example 7: Create service products -echo "7. Creating service products\n"; +// Example 8: Create service products +echo "8. Creating service products\n"; echo "----------------------------\n"; $serviceProducts = [ @@ -290,7 +308,7 @@ foreach ($serviceProducts as $serviceData) { try { - $serviceResponse = $businessGateway->eInvoiceProductService()->createProduct($serviceData); + $serviceResponse = $businessGateway->invoiceProductService()->createProduct($serviceData); if ($serviceResponse->isSuccessful()) { $responseData = $serviceResponse->getDecodeResponse(); @@ -309,14 +327,14 @@ echo "\n"; -// Example 8: Delete product -echo "8. Deleting product\n"; -echo "-------------------\n"; +// Example 10: Delete product +echo "10. Deleting product\n"; +echo "--------------------\n"; $productToDelete = 'PD-DELETE-' . time(); try { - $deleteResponse = $businessGateway->eInvoiceProductService()->deleteProduct($productToDelete); + $deleteResponse = $businessGateway->invoiceProductService()->deleteProduct($productToDelete); if ($deleteResponse->isSuccessful()) { echo "Product deleted successfully\n"; @@ -328,7 +346,7 @@ echo "Exception: " . $e->getMessage() . "\n"; } -echo "\nE-Invoice Product API examples completed!\n"; +echo "\nInvoice Product API examples completed!\n"; echo "Use cases:\n"; echo "• Product catalog management\n"; echo "• Multi-currency pricing\n"; diff --git a/code-samples/business/e-invoice/tax.php b/code-samples/business/e-invoice/tax.php index 1155682..6e9a336 100644 --- a/code-samples/business/e-invoice/tax.php +++ b/code-samples/business/e-invoice/tax.php @@ -5,72 +5,71 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1, ]); -echo "FasterPay E-Invoice Tax API Examples\n"; -echo "====================================\n\n"; +echo "FasterPay Invoice Tax API Examples\n"; +echo "===================================\n\n"; -// Example 1: Create a flat tax -echo "1. Creating a flat tax\n"; -echo "----------------------\n"; +// Example 1: Create a basic percentage tax +echo "1. Creating a basic percentage tax\n"; +echo "----------------------------------\n"; -$flatTaxData = [ - 'name' => 'Processing Fee', - 'type' => 'flat', - 'value' => 2.50, - 'description' => 'Fixed processing fee per transaction' +$taxData = [ + 'name' => 'Sales Tax', + 'type' => 'percentage', + 'value' => 8.5, + 'description' => '8.5% sales tax for California' ]; try { - $taxResponse = $businessGateway->eInvoiceTaxService()->createTax($flatTaxData); + $taxResponse = $businessGateway->invoiceTaxService()->createTax($taxData); if ($taxResponse->isSuccessful()) { - echo "✓ Flat tax created successfully\n"; + echo "Tax created successfully\n"; $responseData = $taxResponse->getDecodeResponse(); $taxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-' . time(); echo " Tax ID: " . $taxId . "\n"; - echo " Name: " . $flatTaxData['name'] . "\n"; - echo " Type: " . $flatTaxData['type'] . "\n"; - echo " Value: $" . number_format($flatTaxData['value'], 2) . "\n"; - echo " Description: " . $flatTaxData['description'] . "\n"; + echo " Name: " . $taxData['name'] . "\n"; + echo " Type: " . $taxData['type'] . "\n"; + echo " Rate: " . $taxData['value'] . "%\n"; + echo " Description: " . $taxData['description'] . "\n"; } else { - echo "✗ Error: " . $taxResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $taxResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 2: Create a percentage tax -echo "2. Creating a percentage tax\n"; -echo "----------------------------\n"; +// Example 2: Create a flat fee tax +echo "2. Creating a flat fee tax\n"; +echo "---------------------------\n"; -$percentageTaxData = [ - 'name' => 'Sales Tax', - 'type' => 'percentage', - 'value' => 8.25, - 'description' => '8.25% state sales tax' +$flatTaxData = [ + 'name' => 'Processing Fee', + 'type' => 'flat', + 'value' => 2.50, + 'currency' => 'USD', + 'description' => '$2.50 flat processing fee per transaction' ]; try { - $salesTaxResponse = $businessGateway->eInvoiceTaxService()->createTax($percentageTaxData); - - if ($salesTaxResponse->isSuccessful()) { - echo "✓ Percentage tax created successfully\n"; - $responseData = $salesTaxResponse->getDecodeResponse(); - $salesTaxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-SALES-' . time(); - echo " Tax ID: " . $salesTaxId . "\n"; - echo " Name: " . $percentageTaxData['name'] . "\n"; - echo " Type: " . $percentageTaxData['type'] . "\n"; - echo " Value: " . $percentageTaxData['value'] . "%\n"; - echo " Description: " . $percentageTaxData['description'] . "\n"; + $flatTaxResponse = $businessGateway->invoiceTaxService()->createTax($flatTaxData); + + if ($flatTaxResponse->isSuccessful()) { + echo "Flat tax created successfully\n"; + $responseData = $flatTaxResponse->getDecodeResponse(); + $flatTaxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-FLAT-' . time(); + echo " Tax ID: " . $flatTaxId . "\n"; + echo " Name: " . $flatTaxData['name'] . "\n"; + echo " Type: " . $flatTaxData['type'] . "\n"; + echo " Value: $" . $flatTaxData['value'] . " " . $flatTaxData['currency'] . "\n"; } else { - echo "✗ Error: " . $salesTaxResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $flatTaxResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -80,58 +79,57 @@ echo "-------------------\n"; $vatTaxData = [ - 'name' => 'VAT', + 'name' => 'VAT (UK)', 'type' => 'percentage', - 'value' => 20, - 'description' => '20% Value Added Tax' + 'value' => 20.0, + 'description' => '20% VAT for United Kingdom transactions' ]; try { - $vatResponse = $businessGateway->eInvoiceTaxService()->createTax($vatTaxData); + $vatResponse = $businessGateway->invoiceTaxService()->createTax($vatTaxData); if ($vatResponse->isSuccessful()) { - echo "✓ VAT tax created successfully\n"; + echo "VAT tax created successfully\n"; $responseData = $vatResponse->getDecodeResponse(); $vatTaxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-VAT-' . time(); echo " Tax ID: " . $vatTaxId . "\n"; echo " Name: " . $vatTaxData['name'] . "\n"; - echo " Type: " . $vatTaxData['type'] . "\n"; - echo " Value: " . $vatTaxData['value'] . "%\n"; - echo " Description: " . $vatTaxData['description'] . "\n"; + echo " Rate: " . $vatTaxData['value'] . "%\n"; + echo " Region: United Kingdom\n"; } else { - echo "✗ Error: " . $vatResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $vatResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; // Example 4: Get tax details -echo "4. Retrieving tax details\n"; -echo "-------------------------\n"; +echo "4. Getting tax details\n"; +echo "----------------------\n"; -$testTaxId = isset($taxId) ? $taxId : 'TX-250527-2E9N'; +$taxId = isset($taxId) ? $taxId : 'TX-' . time(); try { - $getTaxResponse = $businessGateway->eInvoiceTaxService()->getTax($testTaxId); - - if ($getTaxResponse->isSuccessful()) { - echo "✓ Tax details retrieved successfully\n"; - $taxData = $getTaxResponse->getDecodeResponse(); - if (isset($taxData['data'])) { - $tax = $taxData['data']; - echo " Tax ID: " . (isset($tax['id']) ? $tax['id'] : $testTaxId) . "\n"; - echo " Name: " . (isset($tax['name']) ? $tax['name'] : 'N/A') . "\n"; - echo " Type: " . (isset($tax['type']) ? $tax['type'] : 'N/A') . "\n"; - echo " Value: " . (isset($tax['value']) ? $tax['value'] : 'N/A') . "\n"; - echo " Description: " . (isset($tax['description']) ? $tax['description'] : 'N/A') . "\n"; - } + $detailsResponse = $businessGateway->invoiceTaxService()->getTax($taxId); + + if ($detailsResponse->isSuccessful()) { + echo "Tax details retrieved\n"; + $details = $detailsResponse->getDecodeResponse(); + $tax = isset($details['data']) ? $details['data'] : []; + + echo " ID: " . (isset($tax['id']) ? $tax['id'] : $taxId) . "\n"; + echo " Name: " . (isset($tax['name']) ? $tax['name'] : 'N/A') . "\n"; + echo " Type: " . (isset($tax['type']) ? $tax['type'] : 'N/A') . "\n"; + echo " Value: " . (isset($tax['value']) ? $tax['value'] : '0') . "\n"; + echo " Currency: " . (isset($tax['currency']) ? $tax['currency'] : 'N/A') . "\n"; + echo " Description: " . (isset($tax['description']) ? $tax['description'] : 'N/A') . "\n"; } else { - echo "✗ Error: " . $getTaxResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -140,217 +138,125 @@ echo "5. Updating tax\n"; echo "---------------\n"; -$updateTaxData = [ - 'name' => 'Updated Processing Fee', - 'description' => 'Updated processing fee with new rate', - 'value' => 3.00 +$updateData = [ + 'name' => 'Updated Sales Tax', + 'value' => 9.0, + 'description' => 'Updated 9% sales tax rate' ]; try { - $updateResponse = $businessGateway->eInvoiceTaxService()->updateTax($testTaxId, $updateTaxData); + $updateResponse = $businessGateway->invoiceTaxService()->updateTax($taxId, $updateData); if ($updateResponse->isSuccessful()) { - echo "✓ Tax updated successfully\n"; - echo " Tax ID: " . $testTaxId . "\n"; - echo " Updated Name: " . $updateTaxData['name'] . "\n"; - echo " Updated Value: $" . number_format($updateTaxData['value'], 2) . "\n"; - echo " Updated Description: " . $updateTaxData['description'] . "\n"; + echo "Tax updated successfully\n"; + echo " Updated rate to: " . $updateData['value'] . "%\n"; + echo " Updated description\n"; } else { - echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 6: List taxes -echo "6. Listing taxes\n"; -echo "----------------\n"; +// Example 6: List all taxes +echo "6. Listing all taxes\n"; +echo "--------------------\n"; -$filters = [ - 'limit' => 10, - 'offset' => 0 +$listFilters = [ + 'page' => 1, + 'per_page' => 10 ]; try { - $listResponse = $businessGateway->eInvoiceTaxService()->listTaxes($filters); + $listResponse = $businessGateway->invoiceTaxService()->listTaxes($listFilters); if ($listResponse->isSuccessful()) { - echo "✓ Tax list retrieved successfully\n"; + echo "Tax list retrieved\n"; $listData = $listResponse->getDecodeResponse(); - if (isset($listData['data']) && is_array($listData['data'])) { - echo " Found " . count($listData['data']) . " taxes:\n"; - foreach ($listData['data'] as $tax) { - $id = isset($tax['id']) ? $tax['id'] : 'Unknown'; - $name = isset($tax['name']) ? $tax['name'] : 'Unnamed'; - $type = isset($tax['type']) ? $tax['type'] : 'Unknown'; - $value = isset($tax['value']) ? $tax['value'] : '0'; - echo " - " . $name . " (" . $id . ") - " . $type . ": " . $value . "\n"; - } + $taxes = isset($listData['data']['data']) ? $listData['data']['data'] : []; + + echo " Found " . count($taxes) . " taxes\n"; + foreach ($taxes as $tax) { + $id = isset($tax['id']) ? $tax['id'] : 'Unknown'; + $name = isset($tax['name']) ? $tax['name'] : 'Unnamed'; + $type = isset($tax['type']) ? $tax['type'] : 'unknown'; + $value = isset($tax['value']) ? $tax['value'] : '0'; + echo " - $name ($type: $value) - ID: $id\n"; } } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 7: Delete tax -echo "7. Deleting tax\n"; -echo "---------------\n"; - -$deleteTestTaxId = isset($vatTaxId) ? $vatTaxId : 'TX-DELETE-' . time(); - -try { - $deleteResponse = $businessGateway->eInvoiceTaxService()->deleteTax($deleteTestTaxId); - - if ($deleteResponse->isSuccessful()) { - echo "✓ Tax deleted successfully\n"; - echo " Deleted Tax ID: " . $deleteTestTaxId . "\n"; - } else { - echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} +// Example 7: Create multiple regional taxes +echo "7. Creating multiple regional taxes\n"; +echo "-----------------------------------\n"; -echo "\n"; - -// Example 8: Using taxes in invoices (embedded tax object) -echo "8. Using taxes in invoices\n"; -echo "--------------------------\n"; - -$invoiceWithTaxData = [ - 'currency' => 'USD', - 'summary' => 'Invoice with embedded tax', - 'number' => 'INV-TAX-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => 'CT-250527-AZARCIJE', - 'tax' => [ - 'name' => 'Service Tax', +$regionalTaxes = [ + [ + 'name' => 'New York State Tax', 'type' => 'percentage', - 'value' => 5, - 'description' => '5% service tax' + 'value' => 8.25, + 'description' => '8.25% sales tax for New York State' ], - 'items' => [ - [ - 'price' => 100.00, - 'quantity' => 1, - 'name' => 'Consulting Service', - 'description' => 'Professional consulting service' - ] + [ + 'name' => 'Texas State Tax', + 'type' => 'percentage', + 'value' => 6.25, + 'description' => '6.25% sales tax for Texas' + ], + [ + 'name' => 'European VAT', + 'type' => 'percentage', + 'value' => 19.0, + 'description' => '19% VAT for European Union' ] ]; -try { - $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceWithTaxData); - - if ($invoiceResponse->isSuccessful()) { - echo "✓ Invoice with embedded tax created successfully\n"; - $responseData = $invoiceResponse->getDecodeResponse(); - $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Invoice Number: " . $invoiceWithTaxData['number'] . "\n"; - echo " Tax: " . $invoiceWithTaxData['tax']['name'] . " (" . $invoiceWithTaxData['tax']['value'] . "%)\n"; - } else { - echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} => 0 -); - -try { - $listResponse = $businessGateway->eInvoiceTaxService()->listTaxes($filters); +foreach ($regionalTaxes as $taxData) { + try { + $response = $businessGateway->invoiceTaxService()->createTax($taxData); - if ($listResponse->isSuccessful()) { - echo "✓ Tax list retrieved successfully\n"; - $listData = $listResponse->getDecodeResponse(); - if (isset($listData['data']) && is_array($listData['data'])) { - echo " Found " . count($listData['data']) . " taxes:\n"; - foreach ($listData['data'] as $tax) { - $id = isset($tax['id']) ? $tax['id'] : 'Unknown'; - $name = isset($tax['name']) ? $tax['name'] : 'Unnamed'; - $type = isset($tax['type']) ? $tax['type'] : 'Unknown'; - $value = isset($tax['value']) ? $tax['value'] : '0'; - echo " - " . $name . " (" . $id . ") - " . $type . ": " . $value . "\n"; - } + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $id = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-REGION-' . time(); + echo " Created: {$taxData['name']} ({$taxData['value']}%) - ID: $id\n"; + } else { + echo " Error creating {$taxData['name']}: " . $response->getErrors()->getMessage() . "\n"; } - } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + } catch (FasterPay\Exception $e) { + echo " Exception creating {$taxData['name']}: " . $e->getMessage() . "\n"; } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 7: Delete tax -echo "7. Deleting tax\n"; -echo "---------------\n"; +// Example 8: Delete tax +echo "8. Deleting tax\n"; +echo "----------------\n"; -$deleteTestTaxId = isset($vatTaxId) ? $vatTaxId : 'TX-DELETE-' . time(); +$deleteTaxId = isset($vatTaxId) ? $vatTaxId : 'TX-DELETE-' . time(); try { - $deleteResponse = $businessGateway->eInvoiceTaxService()->deleteTax($deleteTestTaxId); + $deleteResponse = $businessGateway->invoiceTaxService()->deleteTax($deleteTaxId); if ($deleteResponse->isSuccessful()) { - echo "✓ Tax deleted successfully\n"; - echo " Deleted Tax ID: " . $deleteTestTaxId . "\n"; - } else { - echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 8: Using taxes in invoices (embedded tax object) -echo "8. Using taxes in invoices\n"; -echo "--------------------------\n"; - -$invoiceWithTaxData = array( - 'currency' => 'USD', - 'summary' => 'Invoice with embedded tax', - 'number' => 'INV-TAX-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => 'CT-250527-AZARCIJE', - 'tax' => array( - 'name' => 'Service Tax', - 'type' => 'percentage', - 'value' => 5, - 'description' => '5% service tax' - ), - 'items' => array( - array( - 'price' => 100.00, - 'quantity' => 1, - 'name' => 'Consulting Service', - 'description' => 'Professional consulting service' - ) - ) -); - -try { - $invoiceResponse = $businessGateway->eInvoiceService()->createInvoice($invoiceWithTaxData); - - if ($invoiceResponse->isSuccessful()) { - echo "✓ Invoice with embedded tax created successfully\n"; - $responseData = $invoiceResponse->getDecodeResponse(); - $invoiceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'FPBIV-' . time(); - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Invoice Number: " . $invoiceWithTaxData['number'] . "\n"; - echo " Tax: " . $invoiceWithTaxData['tax']['name'] . " (" . $invoiceWithTaxData['tax']['value'] . "%)\n"; + echo "Tax deleted successfully\n"; + echo " Deleted Tax ID: " . $deleteTaxId . "\n"; } else { - echo "✗ Error: " . $invoiceResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } -echo "\nE-Invoice Tax API examples completed!\n"; +echo "\nInvoice Tax API examples completed!\n"; echo "Use cases:\n"; echo "• Sales tax calculation and management\n"; echo "• VAT handling for international transactions\n"; @@ -359,4 +265,18 @@ echo "• Custom tax rates per region\n"; echo "• Tax exemption handling\n"; echo "• Multi-jurisdiction tax support\n"; -echo "• Automated tax calculation in invoices\n"; \ No newline at end of file +echo "• Automated tax calculation in invoices\n"; +echo "• Flat fee vs percentage tax options\n"; +echo "• Regional tax configuration\n"; + +echo "\nTax Types:\n"; +echo "• percentage: Tax calculated as percentage of amount\n"; +echo "• flat: Fixed tax amount regardless of invoice total\n"; + +echo "\nValidation Notes:\n"; +echo "• Only ID field validation implemented (as requested)\n"; +echo "• API handles all parameter validation server-side\n"; +echo "• Tax values for percentage type should be decimal (8.5 for 8.5%)\n"; +echo "• Tax values for flat type should be monetary amount\n"; +echo "• Currency required for flat type taxes\n"; +echo "• Tax names limited to 191 characters\n"; \ No newline at end of file diff --git a/code-samples/business/e-invoice/template.php b/code-samples/business/e-invoice/template.php index 50e6dc7..48348b2 100644 --- a/code-samples/business/e-invoice/template.php +++ b/code-samples/business/e-invoice/template.php @@ -5,11 +5,10 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1, ]); -echo "FasterPay E-Invoice Template API Examples\n"; -echo "==========================================\n\n"; +echo "FasterPay Invoice Template API Examples\n"; +echo "========================================\n\n"; // Example 1: Create a new invoice template echo "1. Creating a new invoice template\n"; @@ -32,17 +31,17 @@ ]; try { - $templateResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($templateData); + $templateResponse = $businessGateway->invoiceTemplateService()->createTemplate($templateData); if ($templateResponse->isSuccessful()) { echo "Template created successfully\n"; $responseData = $templateResponse->getDecodeResponse(); - $templateId = $responseData['data']['id'] ?? 'IT-' . time(); + $templateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-' . time(); echo " Template ID: $templateId\n"; echo " Name: {$templateData['name']}\n"; echo " Primary Color: {$templateData['colors']['primary']}\n"; echo " Address: {$templateData['localized_address']['address_line1']}, {$templateData['localized_address']['locality']}\n"; - echo " Full Address: " . ($responseData['data']['full_address'] ?? 'Generated automatically') . "\n"; + echo " Full Address: " . (isset($responseData['data']['full_address']) ? $responseData['data']['full_address'] : 'Generated automatically') . "\n"; } else { echo "Error: " . $templateResponse->getErrors()->getMessage() . "\n"; } @@ -52,43 +51,6 @@ echo "\n"; -// Example 4.5: Update template with logo -echo "4.5 Updating template with logo\n"; -echo "--------------------------------\n"; - -$updateWithLogoData = [ - 'footer' => 'Updated template with new branding and logo!', - 'colors' => [ - 'primary' => '#7c2d12', - 'secondary' => '#fef7ed' - ], - 'logo' => '/path/to/updated-logo.jpg' // File path provided directly in params -]; - -try { - // Note: In real implementation, provide actual logo file path in params['logo'] - // The service automatically detects file fields and uses multipart upload with _method=PUT - - // For demo purposes, update without logo - $demoUpdateData = $updateWithLogoData; - unset($demoUpdateData['logo']); // Remove for demo - $updateLogoResponse = $businessGateway->eInvoiceTemplateService()->updateTemplate($templateId, $demoUpdateData); - - if ($updateLogoResponse->isSuccessful()) { - echo "Template with logo updated successfully\n"; - echo " Updated footer and branding colors\n"; - echo " Logo: File would be uploaded automatically if 'logo' field contains file path\n"; - echo " Usage: \$params['logo'] = '/path/to/new-file.jpg'\n"; - echo " Method: Automatically uses POST + _method=PUT for file uploads\n"; - } else { - echo "Error: " . $updateLogoResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - // Example 1.5: Create template with logo upload echo "1.5 Creating template with logo\n"; echo "--------------------------------\n"; @@ -113,16 +75,16 @@ try { // Note: In real implementation, provide actual logo file path in params['logo'] // The service automatically detects file fields and uses multipart upload - + // For demo purposes, create without logo $demoData = $templateWithLogoData; unset($demoData['logo']); // Remove for demo - $logoResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($demoData); + $logoResponse = $businessGateway->invoiceTemplateService()->createTemplate($demoData); if ($logoResponse->isSuccessful()) { echo "Template with logo created successfully\n"; $responseData = $logoResponse->getDecodeResponse(); - $logoTemplateId = $responseData['data']['id'] ?? 'IT-LOGO-' . time(); + $logoTemplateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-LOGO-' . time(); echo " Template ID: $logoTemplateId\n"; echo " Name: {$templateWithLogoData['name']}\n"; echo " Logo: File would be uploaded automatically if 'logo' field contains file path\n"; @@ -158,12 +120,12 @@ ]; try { - $brandedResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($brandedTemplateData); + $brandedResponse = $businessGateway->invoiceTemplateService()->createTemplate($brandedTemplateData); if ($brandedResponse->isSuccessful()) { echo "Branded template created successfully\n"; $responseData = $brandedResponse->getDecodeResponse(); - $brandedTemplateId = $responseData['data']['id'] ?? 'IT-BRAND-' . time(); + $brandedTemplateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-BRAND-' . time(); echo " Template ID: $brandedTemplateId\n"; echo " Brand Colors: {$brandedTemplateData['colors']['primary']} / {$brandedTemplateData['colors']['secondary']}\n"; echo " Corporate Address: {$brandedTemplateData['localized_address']['address_line1']}\n"; @@ -180,26 +142,26 @@ echo "3. Getting template details\n"; echo "---------------------------\n"; -$templateId = $templateId ?? 'IT-' . time(); +$templateId = isset($templateId) ? $templateId : 'IT-' . time(); try { - $detailsResponse = $businessGateway->eInvoiceTemplateService()->getTemplate($templateId); + $detailsResponse = $businessGateway->invoiceTemplateService()->getTemplate($templateId); if ($detailsResponse->isSuccessful()) { echo "Template details retrieved\n"; - $details = $detailsResponse->getDecodeResponse(); - $template = $details['data'] ?? []; - - echo " ID: " . ($template['id'] ?? $templateId) . "\n"; - echo " Name: " . ($template['name'] ?? 'N/A') . "\n"; - echo " Country: " . ($template['country_code'] ?? 'N/A') . "\n"; - echo " Footer: " . ($template['footer'] ?? 'N/A') . "\n"; - + $details = isset($detailsResponse->getDecodeResponse()['data']) ? $detailsResponse->getDecodeResponse()['data'] : []; + $template = $details; + + echo " ID: " . (isset($template['id']) ? $template['id'] : $templateId) . "\n"; + echo " Name: " . (isset($template['name']) ? $template['name'] : 'N/A') . "\n"; + echo " Country: " . (isset($template['country_code']) ? $template['country_code'] : 'N/A') . "\n"; + echo " Footer: " . (isset($template['footer']) ? $template['footer'] : 'N/A') . "\n"; + if (isset($template['colors'])) { - echo " Primary Color: " . ($template['colors']['primary'] ?? 'N/A') . "\n"; - echo " Secondary Color: " . ($template['colors']['secondary'] ?? 'N/A') . "\n"; + echo " Primary Color: " . (isset($template['colors']['primary']) ? $template['colors']['primary'] : 'N/A') . "\n"; + echo " Secondary Color: " . (isset($template['colors']['secondary']) ? $template['colors']['secondary'] : 'N/A') . "\n"; } - + if (isset($template['full_address'])) { echo " Full Address: " . $template['full_address'] . "\n"; } @@ -225,7 +187,7 @@ ]; try { - $updateResponse = $businessGateway->eInvoiceTemplateService()->updateTemplate($templateId, $updateData); + $updateResponse = $businessGateway->invoiceTemplateService()->updateTemplate($templateId, $updateData); if ($updateResponse->isSuccessful()) { echo "Template updated successfully\n"; @@ -240,6 +202,43 @@ echo "\n"; +// Example 4.5: Update template with logo +echo "4.5 Updating template with logo\n"; +echo "--------------------------------\n"; + +$updateWithLogoData = [ + 'footer' => 'Updated template with new branding and logo!', + 'colors' => [ + 'primary' => '#7c2d12', + 'secondary' => '#fef7ed' + ], + 'logo' => '/path/to/updated-logo.jpg' // File path provided directly in params +]; + +try { + // Note: In real implementation, provide actual logo file path in params['logo'] + // The service automatically detects file fields and uses multipart upload with _method=PUT + + // For demo purposes, update without logo + $demoUpdateData = $updateWithLogoData; + unset($demoUpdateData['logo']); // Remove for demo + $updateLogoResponse = $businessGateway->invoiceTemplateService()->updateTemplate($templateId, $demoUpdateData); + + if ($updateLogoResponse->isSuccessful()) { + echo "Template with logo updated successfully\n"; + echo " Updated footer and branding colors\n"; + echo " Logo: File would be uploaded automatically if 'logo' field contains file path\n"; + echo " Usage: \$params['logo'] = '/path/to/new-file.jpg'\n"; + echo " Method: Automatically uses POST + _method=PUT for file uploads\n"; + } else { + echo "Error: " . $updateLogoResponse->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo "Exception: " . $e->getMessage() . "\n"; +} + +echo "\n"; + // Example 5: List all templates echo "5. Listing all templates\n"; echo "------------------------\n"; @@ -250,25 +249,18 @@ ]; try { - $listResponse = $businessGateway->eInvoiceTemplateService()->listTemplates($listFilters); + $listResponse = $businessGateway->invoiceTemplateService()->listTemplates($listFilters); if ($listResponse->isSuccessful()) { echo "Templates list retrieved\n"; $listData = $listResponse->getDecodeResponse(); - $templates = $listData['data']['data'] ?? []; - - echo " Total templates: " . count($templates) . "\n"; - echo " Current page: " . ($listData['data']['current_page'] ?? 1) . "\n"; - echo " Per page: " . ($listData['data']['per_page'] ?? 10) . "\n"; + $templates = isset($listData['data']['data']) ? $listData['data']['data'] : []; - if (!empty($templates)) { - echo " Templates:\n"; - foreach ($templates as $template) { - $id = $template['id'] ?? 'Unknown'; - $name = $template['name'] ?? 'Unnamed'; - $country = $template['country_code'] ?? 'N/A'; - echo " - $name ($id) - Country: $country\n"; - } + echo " Found " . count($templates) . " templates\n"; + foreach ($templates as $template) { + $id = isset($template['id']) ? $template['id'] : 'Unknown'; + $name = isset($template['name']) ? $template['name'] : 'Unnamed'; + echo " - $name ($id)\n"; } } else { echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; @@ -279,16 +271,16 @@ echo "\n"; -// Example 6: Create template for different country -echo "6. Creating template for UK\n"; -echo "---------------------------\n"; +// Example 6: Create UK-specific template +echo "6. Creating UK-specific template\n"; +echo "--------------------------------\n"; $ukTemplateData = [ - 'name' => 'UK Template', - 'footer' => 'Registered in England and Wales', + 'name' => 'UK Business Template', + 'footer' => 'Registered in England and Wales. Company No: 12345678. VAT No: GB123456789', 'colors' => [ 'primary' => '#1e40af', - 'secondary' => '#eff6ff' + 'secondary' => '#f1f5f9' ], 'localized_address' => [ 'address_line1' => '10 Downing Street', @@ -299,15 +291,15 @@ ]; try { - $ukResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($ukTemplateData); + $ukResponse = $businessGateway->invoiceTemplateService()->createTemplate($ukTemplateData); if ($ukResponse->isSuccessful()) { echo "UK template created successfully\n"; $responseData = $ukResponse->getDecodeResponse(); - $ukTemplateId = $responseData['data']['id'] ?? 'IT-UK-' . time(); + $ukTemplateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-UK-' . time(); echo " Template ID: $ukTemplateId\n"; - echo " Country: GB (United Kingdom)\n"; - echo " Address format: UK postal code format\n"; + echo " UK Address: {$ukTemplateData['localized_address']['address_line1']}, {$ukTemplateData['localized_address']['locality']}\n"; + echo " Postal Code: {$ukTemplateData['localized_address']['postal_code']}\n"; } else { echo "Error: " . $ukResponse->getErrors()->getMessage() . "\n"; } @@ -317,33 +309,35 @@ echo "\n"; -// Example 7: Create template with generic address -echo "7. Creating template with generic address\n"; -echo "-----------------------------------------\n"; +// Example 7: Search templates by name +echo "7. Searching templates by name\n"; +echo "------------------------------\n"; -$genericTemplateData = [ - 'name' => 'Generic Address Template', - 'address' => '789 International Blvd, Global City, GC 12345, World', - 'footer' => 'International Business Solutions', - 'colors' => [ - 'primary' => '#7c3aed', - 'secondary' => '#f3e8ff' - ], - 'country_code' => 'XX' +$searchFilters = [ + 'filter' => 'Professional', + 'per_page' => 5 ]; try { - $genericResponse = $businessGateway->eInvoiceTemplateService()->createTemplate($genericTemplateData); - - if ($genericResponse->isSuccessful()) { - echo "Generic template created successfully\n"; - $responseData = $genericResponse->getDecodeResponse(); - $genericTemplateId = $responseData['data']['id'] ?? 'IT-GENERIC-' . time(); - echo " Template ID: $genericTemplateId\n"; - echo " Generic Address: {$genericTemplateData['address']}\n"; - echo " Country: {$genericTemplateData['country_code']}\n"; + $searchResponse = $businessGateway->invoiceTemplateService()->listTemplates($searchFilters); + + if ($searchResponse->isSuccessful()) { + echo "Template search completed\n"; + $searchData = $searchResponse->getDecodeResponse(); + $templates = isset($searchData['data']['data']) ? $searchData['data']['data'] : []; + + if (count($templates) > 0) { + echo " Found " . count($templates) . " matching templates:\n"; + foreach ($templates as $template) { + $id = isset($template['id']) ? $template['id'] : 'Unknown'; + $name = isset($template['name']) ? $template['name'] : 'Unnamed'; + echo " - $name ($id)\n"; + } + } else { + echo " No templates found matching 'Professional'\n"; + } } else { - echo "Error: " . $genericResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $searchResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -351,41 +345,45 @@ echo "\n"; -// Example 8: Search templates with filters -echo "8. Searching templates with name filter\n"; -echo "---------------------------------------\n"; +// Example 8: Bulk template operations +echo "8. Bulk template operations\n"; +echo "---------------------------\n"; -$searchFilters = [ - 'page' => 1, - 'per_page' => 5, - 'filter' => [ - 'name' => 'Professional' +$bulkTemplates = [ + [ + 'name' => 'Minimal Template', + 'footer' => 'Simple and clean invoice design', + 'colors' => ['primary' => '#374151', 'secondary' => '#f9fafb'] + ], + [ + 'name' => 'Corporate Template', + 'footer' => 'Professional corporate invoice template', + 'colors' => ['primary' => '#1f2937', 'secondary' => '#f3f4f6'] ] ]; -try { - $searchResponse = $businessGateway->eInvoiceTemplateService()->listTemplates($searchFilters); - - if ($searchResponse->isSuccessful()) { - echo "Template search completed\n"; - $searchData = $searchResponse->getDecodeResponse(); - $searchResults = $searchData['data']['data'] ?? []; +foreach ($bulkTemplates as $templateData) { + $templateData['country_code'] = 'US'; + $templateData['localized_address'] = [ + 'address_line1' => '123 Business St', + 'locality' => 'Business City', + 'administrative_area' => 'CA', + 'postal_code' => '90210' + ]; - echo " Search filter: name contains 'Professional'\n"; - echo " Found templates: " . count($searchResults) . "\n"; + try { + $response = $businessGateway->invoiceTemplateService()->createTemplate($templateData); - if (!empty($searchResults)) { - foreach ($searchResults as $template) { - $id = $template['id'] ?? 'Unknown'; - $name = $template['name'] ?? 'Unnamed'; - echo " - $name ($id)\n"; - } + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $id = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-BULK-' . time(); + echo " Created: {$templateData['name']} (ID: $id)\n"; + } else { + echo " Error creating {$templateData['name']}: " . $response->getErrors()->getMessage() . "\n"; } - } else { - echo "Error: " . $searchResponse->getErrors()->getMessage() . "\n"; + } catch (FasterPay\Exception $e) { + echo " Exception creating {$templateData['name']}: " . $e->getMessage() . "\n"; } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -394,10 +392,10 @@ echo "9. Deleting a template\n"; echo "----------------------\n"; -$deleteTemplateId = $ukTemplateId ?? 'IT-DELETE-' . time(); +$deleteTemplateId = isset($ukTemplateId) ? $ukTemplateId : 'IT-DELETE-' . time(); try { - $deleteResponse = $businessGateway->eInvoiceTemplateService()->deleteTemplate($deleteTemplateId); + $deleteResponse = $businessGateway->invoiceTemplateService()->deleteTemplate($deleteTemplateId); if ($deleteResponse->isSuccessful()) { echo "Template deleted successfully\n"; @@ -409,7 +407,7 @@ echo "Exception: " . $e->getMessage() . "\n"; } -echo "\nE-Invoice Template API examples completed!\n"; +echo "\nInvoice Template API examples completed!\n"; echo "Use cases:\n"; echo "- Brand-consistent invoice design\n"; echo "- Multi-country invoice templates\n"; diff --git a/code-samples/business/payout.php b/code-samples/business/payout.php index 0edebf1..adc383f 100644 --- a/code-samples/business/payout.php +++ b/code-samples/business/payout.php @@ -5,7 +5,6 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1 ]); echo "=== FasterPay Mass Payout API Examples ===\n\n"; @@ -47,10 +46,10 @@ if ($massPayoutResponse->isSuccessful()) { echo "Mass payout created successfully\n"; $responseData = $massPayoutResponse->getDecodeResponse(); - + // Extract payout IDs from response for further operations - if (isset($responseData['data']['payouts']) && is_array($responseData['data']['payouts'])) { - foreach ($responseData['data']['payouts'] as $payoutItem) { + if (isset($responseData['data']) && is_array($responseData['data'])) { + foreach ($responseData['data'] as $payoutItem) { $createdPayoutIds[] = $payoutItem['id']; echo "Payout ID: " . $payoutItem['id'] . " - Status: " . $payoutItem['status'] . "\n"; } @@ -71,14 +70,14 @@ if (!empty($createdPayoutIds)) { $payoutId = $createdPayoutIds[0]; // Use first created payout ID echo "Using payout ID from create response: " . $payoutId . "\n"; - + try { $payoutDetails = $businessGateway->payoutService()->getPayoutDetails($payoutId); if ($payoutDetails->isSuccessful()) { echo "Payout details retrieved successfully\n"; $responseData = $payoutDetails->getDecodeResponse(); - + if (isset($responseData['data'])) { $data = $responseData['data']; echo "Payout ID: " . $data['id'] . "\n"; @@ -103,11 +102,8 @@ echo "-----------------------------------\n"; $filters = [ - 'limit' => 20, - 'offset' => 0, - 'status' => 'submitted', - 'from_date' => '2024-01-01', - 'to_date' => '2024-12-31' + 'per_page' => 20, + 'page' => 1, ]; try { @@ -116,12 +112,12 @@ if ($payoutList->isSuccessful()) { echo "Payout list retrieved successfully\n"; $responseData = $payoutList->getDecodeResponse(); - - if (isset($responseData['data']['payouts']) && is_array($responseData['data']['payouts'])) { - echo "Found " . count($responseData['data']['payouts']) . " payouts\n"; - foreach ($responseData['data']['payouts'] as $payout) { - echo "- " . $payout['id'] . " (" . $payout['status'] . ") - " . - $payout['amounts']['target_amount'] . " " . $payout['amounts']['target_currency'] . "\n"; + + if (isset($responseData['data']['data']) && is_array($responseData['data']['data'])) { + echo "Found " . count($responseData['data']['data']) . " payouts\n"; + foreach ($responseData['data']['data'] as $payout) { + echo "- " . $payout['id'] . " (" . $payout['status'] . ") - " . + $payout['amounts']['target_amount'] . " " . $payout['amounts']['target_currency'] . "\n"; } } } else { diff --git a/lib/FasterPay/BusinessGateway.php b/lib/FasterPay/BusinessGateway.php index 2911754..a43f551 100644 --- a/lib/FasterPay/BusinessGateway.php +++ b/lib/FasterPay/BusinessGateway.php @@ -17,13 +17,11 @@ class BusinessGateway implements GatewayInterface { - const BUSINESS_API_BASE_URL = 'https://develop.ma.fasterpay.bamboo.stuffio.com'; - const BUSINESS_API_SANDBOX_BASE_URL = 'https://business.sandbox.fasterpay.com'; + const BUSINESS_API_BASE_URL = 'https://business.fasterpay.com'; protected $config; protected $http; protected $baseUrl = ''; - protected $extraParams = []; public function __construct($config = []) { @@ -32,13 +30,7 @@ public function __construct($config = []) } $this->config = $config; - - // Override the base URL for business APIs - if ($this->config->getIsTest()) { - $this->config->setBaseUrl(self::BUSINESS_API_SANDBOX_BASE_URL); - } else { - $this->config->setBaseUrl(self::BUSINESS_API_BASE_URL); - } + $this->config->setBaseUrl(self::BUSINESS_API_BASE_URL); $header = [ 'X-ApiKey: ' . $this->config->getPrivateKey(), @@ -161,12 +153,4 @@ public function getConfig() { return $this->config; } - - public function callApi($endpoint, array $payload, $method = GenericApiService::HTTP_METHOD_POST, $header = []) - { - $endpoint = $this->getEndPoint($endpoint); - - $service = new GenericApiService(new HttpClient); - return $service->call($endpoint, $payload, $method, $header); - } } \ No newline at end of file diff --git a/lib/FasterPay/Response/JsonResponse.php b/lib/FasterPay/Response/JsonResponse.php new file mode 100644 index 0000000..9b9a258 --- /dev/null +++ b/lib/FasterPay/Response/JsonResponse.php @@ -0,0 +1,48 @@ +getDecodeResponse(); + $httpCode = $this->getHttpCode(); + + // First check HTTP status + if ($httpCode != self::SUCCESS_CODE) { + $errorMessage = empty($response['message']) ? self::RESPONSE_ERROR_TEXT : $response['message']; + $this->errors = new ResponseError([ + 'message' => $errorMessage, + 'code' => $httpCode + ]); + return; + } + + // Then check if response was successfully decoded + if ($response === null) { + $this->errors = new ResponseError([ + 'message' => 'Failed to decode JSON response', + 'code' => self::DEFAULT_ERROR_CODE + ]); + return; + } + + // Check for success flag in response body + if (!empty($response['success'])) { + $this->success = true; + } else { + // Response decoded but success is empty/false/missing + $errorMessage = isset($response['message']) ? $response['message'] : 'Request was not successful'; + $this->errors = new ResponseError([ + 'message' => $errorMessage, + 'code' => isset($response['code']) ? $response['code'] : self::DEFAULT_ERROR_CODE + ]); + } + } + + public function isSuccessful() + { + return $this->success === true && empty($this->errors); + } +} \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Discount.php b/lib/FasterPay/Services/Business/EInvoice/Discount.php index c0dc051..b9875d4 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Discount.php +++ b/lib/FasterPay/Services/Business/EInvoice/Discount.php @@ -63,49 +63,6 @@ public function updateDiscount($discountId = '', array $params = array()) $response = $this->httpService->getHttpClient()->put($endpoint, $params); - return new GeneralResponse($response); - } array $params = array()) - { - if (empty($discountId)) { - throw new Exception('Discount ID is required'); - } - - // Validate discount type if provided - if (!empty($params['type'])) { - $validTypes = array('flat', 'percentage'); - if (!in_array($params['type'], $validTypes)) { - throw new Exception('Discount type must be either "flat" or "percentage"'); - } - } - - // Validate value if provided - if (isset($params['value'])) { - if (!is_numeric($params['value'])) { - throw new Exception('Discount value must be numeric'); - } - - if (!empty($params['type'])) { - if ($params['type'] === 'percentage' && ($params['value'] < 0 || $params['value'] > 100)) { - throw new Exception('Percentage discount value must be between 0 and 100'); - } - - if ($params['type'] === 'flat' && $params['value'] < 0) { - throw new Exception('Flat discount value must be non-negative'); - } - } - } - - // Validate currency for flat discounts - if (!empty($params['type']) && $params['type'] === 'flat' && !empty($params['currency'])) { - if (strlen($params['currency']) !== 3) { - throw new Exception('Currency must be 3 characters (ISO 4217)'); - } - } - - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $discountId); - - $response = $this->httpService->getHttpClient()->put($endpoint, $params); - return new GeneralResponse($response); } diff --git a/lib/FasterPay/Services/Business/Payout.php b/lib/FasterPay/Services/Business/Payout.php index 59ed1db..03c97dd 100644 --- a/lib/FasterPay/Services/Business/Payout.php +++ b/lib/FasterPay/Services/Business/Payout.php @@ -3,7 +3,7 @@ namespace FasterPay\Services\Business; use FasterPay\Exception; -use FasterPay\Response\GeneralResponse; +use FasterPay\Response\JsonResponse; use FasterPay\Services\GeneralService; class Payout extends GeneralService @@ -14,22 +14,22 @@ class Payout extends GeneralService * Create a mass payout * * @param array $params Payout parameters - * @return GeneralResponse + * @return JsonResponse */ - public function createPayout($params = []) + public function createPayout(array $params = []) { $endpoint = $this->httpService->getEndPoint($this->endpoint); $response = $this->httpService->getHttpClient()->post($endpoint, $params); - return new GeneralResponse($response); + return new JsonResponse($response); } /** * Get payout details * * @param string $payoutId Payout ID - * @return GeneralResponse + * @return JsonResponse * @throws Exception */ public function getPayoutDetails($payoutId = '') @@ -42,21 +42,21 @@ public function getPayoutDetails($payoutId = '') $response = $this->httpService->getHttpClient()->get($endpoint); - return new GeneralResponse($response); + return new JsonResponse($response); } /** * Get payout list * * @param array $filters Optional filters (limit, offset, status, etc.) - * @return GeneralResponse + * @return JsonResponse */ - public function getPayoutList($filters = []) + public function getPayoutList(array $filters = []) { $endpoint = $this->httpService->getEndPoint($this->endpoint); $response = $this->httpService->getHttpClient()->get($endpoint, $filters); - return new GeneralResponse($response); + return new JsonResponse($response); } } \ No newline at end of file From c181fb3d76c89815b9f086b329607c3cf7416a21 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 10:10:16 +0700 Subject: [PATCH 08/20] update --- lib/FasterPay/HttpClient.php | 149 +++++++++++++++++------------------ 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/lib/FasterPay/HttpClient.php b/lib/FasterPay/HttpClient.php index bd895a5..7edd625 100644 --- a/lib/FasterPay/HttpClient.php +++ b/lib/FasterPay/HttpClient.php @@ -33,43 +33,26 @@ public function get($endpoint, array $params = [], array $headers = []) return $this->call($endpoint, $params, 'GET', $headers); } - /** - * Send POST request with automatic multipart detection - * - * @param string $endpoint API endpoint - * @param array $params Form parameters - * @param array $headers Additional headers - * @return array - */ public function post($endpoint, array $params = [], array $headers = []) { - // Auto-detect files and use multipart if needed - $files = $this->extractFiles($params); + $testParams = $params; + $files = $this->extractFiles($testParams); if (!empty($files)) { - return $this->postMultipart($endpoint, $params, $files, $headers); + return $this->postMultipart($endpoint, $params, $headers); } return $this->call($endpoint, $params, 'POST', $headers); } - /** - * Send PUT request with automatic multipart detection - * Note: If files detected, uses POST with _method=PUT for multipart compatibility - * - * @param string $endpoint API endpoint - * @param array $params Form parameters - * @param array $headers Additional headers - * @return array - */ public function put($endpoint, array $params = [], array $headers = []) { - // Auto-detect files and use multipart if needed - $files = $this->extractFiles($params); + $testParams = $params; + $files = $this->extractFiles($testParams); if (!empty($files)) { $params['_method'] = 'PUT'; - return $this->postMultipart($endpoint, $params, $files, $headers); + return $this->postMultipart($endpoint, $params, $headers); } return $this->call($endpoint, $params, 'PUT', $headers); @@ -80,22 +63,12 @@ public function delete($endpoint, array $params = [], array $headers = []) return $this->call($endpoint, $params, 'DELETE', $headers); } - /** - * Send multipart POST request with file uploads - * - * @param string $endpoint API endpoint - * @param array $params Form parameters - * @param array $files Array of files where key is field name and value is file path - * @param array $headers Additional headers - * @return array - */ - public function postMultipart($endpoint, array $params = [], array $files = [], array $headers = []) + public function postMultipart($endpoint, array $params = [], array $headers = []) { $ch = $this->init(); $header = array_merge($this->header, $headers); - // Remove Content-Type header to let cURL set it automatically for multipart $header = array_filter($header, function($h) { return stripos($h, 'Content-Type:') !== 0; }); @@ -104,67 +77,93 @@ public function postMultipart($endpoint, array $params = [], array $files = [], curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_URL, $endpoint); - // Prepare multipart data + $files = $this->extractFiles($params); $postData = []; - // Add regular form fields - foreach ($params as $key => $value) { - if (is_array($value)) { - // Handle nested arrays (like colors, localized_address) - foreach ($value as $subKey => $subValue) { - $postData[$key . '[' . $subKey . ']'] = $subValue; - } - } else { - $postData[$key] = $value; - } - } + $this->buildPostData($params, $postData, ''); - // Add files - foreach ($files as $fieldName => $filePath) { - if (file_exists($filePath)) { + foreach ($files as $fieldName => $fileValue) { + if (is_object($fileValue)) { + $postData[$fieldName] = $fileValue; + } elseif (is_string($fileValue) && file_exists($fileValue)) { if (class_exists('CURLFile')) { - // PHP 5.5+ - $postData[$fieldName] = new \CURLFile($filePath); + $postData[$fieldName] = new \CURLFile($fileValue); } else { - // PHP 5.4 compatibility - $postData[$fieldName] = '@' . $filePath; + $postData[$fieldName] = '@' . $fileValue; } } } - curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); - - $response = curl_exec($ch); - $info = curl_getinfo($ch); - curl_close($ch); - return [ 'response' => $response, 'httpCode' => $info['http_code'] ]; } - /** - * Extract file fields from params for multipart upload - * - * @param array $params Reference to params array - * @return array Files array for multipart upload - */ + private function buildPostData(array $data, array &$postData, $prefix) + { + foreach ($data as $key => $value) { + $currentKey = $prefix ? $prefix . '[' . $key . ']' : $key; + + if (is_array($value)) { + $this->buildPostData($value, $postData, $currentKey); + } else { + $postData[$currentKey] = $value; + } + } + } + + private function buildPostData(array $data, array &$postData, $prefix) + { + foreach ($data as $key => $value) { + $currentKey = $prefix ? $prefix . '[' . $key . ']' : $key; + + if (is_array($value)) { + $this->buildPostData($value, $postData, $currentKey); + } else { + $postData[$currentKey] = $value; + } + } + } + private function extractFiles(array &$params) { $files = []; - - foreach ($params as $field => $value) { - if (is_string($value) && !empty($value)) { - // Check if it looks like a file path (not a URL and file exists) - if (!filter_var($value, FILTER_VALIDATE_URL) && file_exists($value)) { - $files[$field] = $value; - unset($params[$field]); // Remove from params as it will be sent as file - } + $this->extractFilesRecursive($params, $files, ''); + return $files; + } + + private function extractFilesRecursive(array &$params, array &$files, $prefix) + { + foreach ($params as $key => $value) { + $currentKey = $prefix ? $prefix . '[' . $key . ']' : $key; + + if (is_array($value)) { + $this->extractFilesRecursive($params[$key], $files, $currentKey); + } elseif ($this->isFileObject($value)) { + $files[$currentKey] = $value; + unset($params[$key]); } } - - return $files; + } + + private function isFileObject($value) + { + if (is_object($value)) { + return $value instanceof \CURLFile || + (class_exists('SplFileInfo') && $value instanceof \SplFileInfo) || + (class_exists('finfo') && method_exists($value, 'getPathname')) || + method_exists($value, '__toString'); + } + + if (is_string($value) && !empty($value)) { + if (filter_var($value, FILTER_VALIDATE_URL)) { + return false; + } + return file_exists($value); + } + + return false; } private function call($endpoint, array $params = [], $method, array $headers = []) From 853aa110dc26e6a832ce173b2c4da02246b78d8e Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 12:17:29 +0700 Subject: [PATCH 09/20] update --- lib/FasterPay/HttpClient.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/FasterPay/HttpClient.php b/lib/FasterPay/HttpClient.php index 7edd625..a52fa65 100644 --- a/lib/FasterPay/HttpClient.php +++ b/lib/FasterPay/HttpClient.php @@ -94,6 +94,12 @@ public function postMultipart($endpoint, array $params = [], array $headers = [] } } + curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); + + $response = curl_exec($ch); + $info = curl_getinfo($ch); + curl_close($ch); + return [ 'response' => $response, 'httpCode' => $info['http_code'] From ded646a19faa49d0060004647d95c4d1a00f1dde Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 12:25:54 +0700 Subject: [PATCH 10/20] update --- code-samples/business/e-invoice/template.php | 390 +++---------------- lib/FasterPay/HttpClient.php | 26 +- 2 files changed, 67 insertions(+), 349 deletions(-) diff --git a/code-samples/business/e-invoice/template.php b/code-samples/business/e-invoice/template.php index 48348b2..1803605 100644 --- a/code-samples/business/e-invoice/template.php +++ b/code-samples/business/e-invoice/template.php @@ -10,13 +10,13 @@ echo "FasterPay Invoice Template API Examples\n"; echo "========================================\n\n"; -// Example 1: Create a new invoice template -echo "1. Creating a new invoice template\n"; -echo "----------------------------------\n"; +// Example 1: Create template +echo "1. Creating template\n"; +echo "--------------------\n"; $templateData = [ 'name' => 'Professional Template', - 'footer' => 'Thank you for your business! Payment terms: Net 30 days.', + 'footer' => 'Thank you for your business!', 'colors' => [ 'primary' => '#2563eb', 'secondary' => '#f8fafc' @@ -27,23 +27,22 @@ 'administrative_area' => 'CA', 'postal_code' => '94105' ], - 'country_code' => 'US' + 'country_code' => 'US', + // 'logo' => '/path/to/logo.png' // Uncomment for logo upload (file path) + // 'logo' => new SplFileInfo('/path/to/logo.png') // Or use SplFileInfo object ]; try { - $templateResponse = $businessGateway->invoiceTemplateService()->createTemplate($templateData); + $response = $businessGateway->invoiceTemplateService()->createTemplate($templateData); - if ($templateResponse->isSuccessful()) { + if ($response->isSuccessful()) { echo "Template created successfully\n"; - $responseData = $templateResponse->getDecodeResponse(); - $templateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-' . time(); + $data = $response->getDecodeResponse(); + $templateId = $data['data']['id'] ?: 'IT-' . time(); echo " Template ID: $templateId\n"; echo " Name: {$templateData['name']}\n"; - echo " Primary Color: {$templateData['colors']['primary']}\n"; - echo " Address: {$templateData['localized_address']['address_line1']}, {$templateData['localized_address']['locality']}\n"; - echo " Full Address: " . (isset($responseData['data']['full_address']) ? $responseData['data']['full_address'] : 'Generated automatically') . "\n"; } else { - echo "Error: " . $templateResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -51,86 +50,28 @@ echo "\n"; -// Example 1.5: Create template with logo upload -echo "1.5 Creating template with logo\n"; -echo "--------------------------------\n"; - -$templateWithLogoData = [ - 'name' => 'Branded Logo Template', - 'footer' => 'Professional template with company logo', - 'colors' => [ - 'primary' => '#e11d48', - 'secondary' => '#fdf2f8' - ], - 'localized_address' => [ - 'address_line1' => '789 Logo Street', - 'locality' => 'Design City', - 'administrative_area' => 'CA', - 'postal_code' => '90210' - ], - 'country_code' => 'US', - 'logo' => '/path/to/company-logo.png' // File path provided directly in params -]; - -try { - // Note: In real implementation, provide actual logo file path in params['logo'] - // The service automatically detects file fields and uses multipart upload - - // For demo purposes, create without logo - $demoData = $templateWithLogoData; - unset($demoData['logo']); // Remove for demo - $logoResponse = $businessGateway->invoiceTemplateService()->createTemplate($demoData); - - if ($logoResponse->isSuccessful()) { - echo "Template with logo created successfully\n"; - $responseData = $logoResponse->getDecodeResponse(); - $logoTemplateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-LOGO-' . time(); - echo " Template ID: $logoTemplateId\n"; - echo " Name: {$templateWithLogoData['name']}\n"; - echo " Logo: File would be uploaded automatically if 'logo' field contains file path\n"; - echo " Usage: \$params['logo'] = '/path/to/file.png'\n"; - } else { - echo "Error: " . $logoResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 2: Create a template with custom branding -echo "2. Creating a branded template\n"; -echo "------------------------------\n"; +// Example 2: Update template +echo "2. Updating template\n"; +echo "--------------------\n"; -$brandedTemplateData = [ - 'name' => 'Company Branded Template', - 'footer' => 'Powered by YourCompany 2024 | www.yourcompany.com', +$updateData = [ + 'footer' => 'Updated footer text', 'colors' => [ - 'primary' => '#ff6b35', - 'secondary' => '#f7f3f0' - ], - 'localized_address' => [ - 'address_line1' => '456 Corporate Blvd', - 'address_line2' => 'Suite 200', - 'locality' => 'New York', - 'administrative_area' => 'NY', - 'postal_code' => '10001' + 'primary' => '#059669', + 'secondary' => '#ecfdf5' ], - 'country_code' => 'US' + // 'logo' => '/path/to/new-logo.png' // Uncomment for logo upload (file path) + // 'logo' => new SplFileInfo('/path/to/new-logo.png') // Or use SplFileInfo object ]; try { - $brandedResponse = $businessGateway->invoiceTemplateService()->createTemplate($brandedTemplateData); + $response = $businessGateway->invoiceTemplateService()->updateTemplate($templateId, $updateData); - if ($brandedResponse->isSuccessful()) { - echo "Branded template created successfully\n"; - $responseData = $brandedResponse->getDecodeResponse(); - $brandedTemplateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-BRAND-' . time(); - echo " Template ID: $brandedTemplateId\n"; - echo " Brand Colors: {$brandedTemplateData['colors']['primary']} / {$brandedTemplateData['colors']['secondary']}\n"; - echo " Corporate Address: {$brandedTemplateData['localized_address']['address_line1']}\n"; + if ($response->isSuccessful()) { + echo "Template updated successfully\n"; + echo " Updated colors and footer\n"; } else { - echo "Error: " . $brandedResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -142,31 +83,20 @@ echo "3. Getting template details\n"; echo "---------------------------\n"; -$templateId = isset($templateId) ? $templateId : 'IT-' . time(); - try { - $detailsResponse = $businessGateway->invoiceTemplateService()->getTemplate($templateId); + $response = $businessGateway->invoiceTemplateService()->getTemplate($templateId); - if ($detailsResponse->isSuccessful()) { + if ($response->isSuccessful()) { echo "Template details retrieved\n"; - $details = isset($detailsResponse->getDecodeResponse()['data']) ? $detailsResponse->getDecodeResponse()['data'] : []; - $template = $details; - - echo " ID: " . (isset($template['id']) ? $template['id'] : $templateId) . "\n"; - echo " Name: " . (isset($template['name']) ? $template['name'] : 'N/A') . "\n"; - echo " Country: " . (isset($template['country_code']) ? $template['country_code'] : 'N/A') . "\n"; - echo " Footer: " . (isset($template['footer']) ? $template['footer'] : 'N/A') . "\n"; - - if (isset($template['colors'])) { - echo " Primary Color: " . (isset($template['colors']['primary']) ? $template['colors']['primary'] : 'N/A') . "\n"; - echo " Secondary Color: " . (isset($template['colors']['secondary']) ? $template['colors']['secondary'] : 'N/A') . "\n"; - } - - if (isset($template['full_address'])) { - echo " Full Address: " . $template['full_address'] . "\n"; - } + $data = $response->getDecodeResponse(); + $template = $data['data'] ?: []; + + echo " ID: " . ($template['id'] ?: $templateId) . "\n"; + echo " Name: " . ($template['name'] ?: 'N/A') . "\n"; + echo " Country: " . ($template['country_code'] ?: 'N/A') . "\n"; + echo " Footer: " . ($template['footer'] ?: 'N/A') . "\n"; } else { - echo "Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -174,170 +104,26 @@ echo "\n"; -// Example 4: Update template -echo "4. Updating template\n"; +// Example 4: List templates +echo "4. Listing templates\n"; echo "--------------------\n"; -$updateData = [ - 'footer' => 'Updated footer - Thank you for choosing our services!', - 'colors' => [ - 'primary' => '#059669', - 'secondary' => '#ecfdf5' - ] -]; - -try { - $updateResponse = $businessGateway->invoiceTemplateService()->updateTemplate($templateId, $updateData); - - if ($updateResponse->isSuccessful()) { - echo "Template updated successfully\n"; - echo " Updated primary color to: {$updateData['colors']['primary']}\n"; - echo " Updated footer\n"; - } else { - echo "Error: " . $updateResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 4.5: Update template with logo -echo "4.5 Updating template with logo\n"; -echo "--------------------------------\n"; - -$updateWithLogoData = [ - 'footer' => 'Updated template with new branding and logo!', - 'colors' => [ - 'primary' => '#7c2d12', - 'secondary' => '#fef7ed' - ], - 'logo' => '/path/to/updated-logo.jpg' // File path provided directly in params -]; - try { - // Note: In real implementation, provide actual logo file path in params['logo'] - // The service automatically detects file fields and uses multipart upload with _method=PUT - - // For demo purposes, update without logo - $demoUpdateData = $updateWithLogoData; - unset($demoUpdateData['logo']); // Remove for demo - $updateLogoResponse = $businessGateway->invoiceTemplateService()->updateTemplate($templateId, $demoUpdateData); - - if ($updateLogoResponse->isSuccessful()) { - echo "Template with logo updated successfully\n"; - echo " Updated footer and branding colors\n"; - echo " Logo: File would be uploaded automatically if 'logo' field contains file path\n"; - echo " Usage: \$params['logo'] = '/path/to/new-file.jpg'\n"; - echo " Method: Automatically uses POST + _method=PUT for file uploads\n"; - } else { - echo "Error: " . $updateLogoResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 5: List all templates -echo "5. Listing all templates\n"; -echo "------------------------\n"; - -$listFilters = [ - 'page' => 1, - 'per_page' => 10 -]; - -try { - $listResponse = $businessGateway->invoiceTemplateService()->listTemplates($listFilters); - - if ($listResponse->isSuccessful()) { - echo "Templates list retrieved\n"; - $listData = $listResponse->getDecodeResponse(); - $templates = isset($listData['data']['data']) ? $listData['data']['data'] : []; + $response = $businessGateway->invoiceTemplateService()->listTemplates(['page' => 1, 'per_page' => 10]); + if ($response->isSuccessful()) { + echo "Templates retrieved successfully\n"; + $data = $response->getDecodeResponse(); + $templates = $data['data']['data'] ?: []; echo " Found " . count($templates) . " templates\n"; + foreach ($templates as $template) { - $id = isset($template['id']) ? $template['id'] : 'Unknown'; - $name = isset($template['name']) ? $template['name'] : 'Unnamed'; + $id = $template['id'] ?: 'Unknown'; + $name = $template['name'] ?: 'Unnamed'; echo " - $name ($id)\n"; } } else { - echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 6: Create UK-specific template -echo "6. Creating UK-specific template\n"; -echo "--------------------------------\n"; - -$ukTemplateData = [ - 'name' => 'UK Business Template', - 'footer' => 'Registered in England and Wales. Company No: 12345678. VAT No: GB123456789', - 'colors' => [ - 'primary' => '#1e40af', - 'secondary' => '#f1f5f9' - ], - 'localized_address' => [ - 'address_line1' => '10 Downing Street', - 'locality' => 'London', - 'postal_code' => 'SW1A 2AA' - ], - 'country_code' => 'GB' -]; - -try { - $ukResponse = $businessGateway->invoiceTemplateService()->createTemplate($ukTemplateData); - - if ($ukResponse->isSuccessful()) { - echo "UK template created successfully\n"; - $responseData = $ukResponse->getDecodeResponse(); - $ukTemplateId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-UK-' . time(); - echo " Template ID: $ukTemplateId\n"; - echo " UK Address: {$ukTemplateData['localized_address']['address_line1']}, {$ukTemplateData['localized_address']['locality']}\n"; - echo " Postal Code: {$ukTemplateData['localized_address']['postal_code']}\n"; - } else { - echo "Error: " . $ukResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 7: Search templates by name -echo "7. Searching templates by name\n"; -echo "------------------------------\n"; - -$searchFilters = [ - 'filter' => 'Professional', - 'per_page' => 5 -]; - -try { - $searchResponse = $businessGateway->invoiceTemplateService()->listTemplates($searchFilters); - - if ($searchResponse->isSuccessful()) { - echo "Template search completed\n"; - $searchData = $searchResponse->getDecodeResponse(); - $templates = isset($searchData['data']['data']) ? $searchData['data']['data'] : []; - - if (count($templates) > 0) { - echo " Found " . count($templates) . " matching templates:\n"; - foreach ($templates as $template) { - $id = isset($template['id']) ? $template['id'] : 'Unknown'; - $name = isset($template['name']) ? $template['name'] : 'Unnamed'; - echo " - $name ($id)\n"; - } - } else { - echo " No templates found matching 'Professional'\n"; - } - } else { - echo "Error: " . $searchResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -345,87 +131,21 @@ echo "\n"; -// Example 8: Bulk template operations -echo "8. Bulk template operations\n"; -echo "---------------------------\n"; - -$bulkTemplates = [ - [ - 'name' => 'Minimal Template', - 'footer' => 'Simple and clean invoice design', - 'colors' => ['primary' => '#374151', 'secondary' => '#f9fafb'] - ], - [ - 'name' => 'Corporate Template', - 'footer' => 'Professional corporate invoice template', - 'colors' => ['primary' => '#1f2937', 'secondary' => '#f3f4f6'] - ] -]; - -foreach ($bulkTemplates as $templateData) { - $templateData['country_code'] = 'US'; - $templateData['localized_address'] = [ - 'address_line1' => '123 Business St', - 'locality' => 'Business City', - 'administrative_area' => 'CA', - 'postal_code' => '90210' - ]; - - try { - $response = $businessGateway->invoiceTemplateService()->createTemplate($templateData); - - if ($response->isSuccessful()) { - $responseData = $response->getDecodeResponse(); - $id = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'IT-BULK-' . time(); - echo " Created: {$templateData['name']} (ID: $id)\n"; - } else { - echo " Error creating {$templateData['name']}: " . $response->getErrors()->getMessage() . "\n"; - } - } catch (FasterPay\Exception $e) { - echo " Exception creating {$templateData['name']}: " . $e->getMessage() . "\n"; - } -} - -echo "\n"; - -// Example 9: Delete a template -echo "9. Deleting a template\n"; -echo "----------------------\n"; - -$deleteTemplateId = isset($ukTemplateId) ? $ukTemplateId : 'IT-DELETE-' . time(); +// Example 5: Delete template +echo "5. Deleting template\n"; +echo "--------------------\n"; try { - $deleteResponse = $businessGateway->invoiceTemplateService()->deleteTemplate($deleteTemplateId); + $response = $businessGateway->invoiceTemplateService()->deleteTemplate($templateId); - if ($deleteResponse->isSuccessful()) { + if ($response->isSuccessful()) { echo "Template deleted successfully\n"; - echo " Deleted Template ID: $deleteTemplateId\n"; + echo " Deleted Template ID: $templateId\n"; } else { - echo "Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; } -echo "\nInvoice Template API examples completed!\n"; -echo "Use cases:\n"; -echo "- Brand-consistent invoice design\n"; -echo "- Multi-country invoice templates\n"; -echo "- Corporate identity management\n"; -echo "- Professional invoice presentation\n"; -echo "- Template reuse across invoices\n"; -echo "- Localized address formatting\n"; -echo "- Custom color schemes and branding\n"; -echo "- Template management and organization\n"; -echo "- Logo upload and branding (multipart/form-data)\n"; -echo "- Server-side validation and processing\n"; - -echo "\nMultipart Support Notes:\n"; -echo "- File auto-detection built into HttpClient - works across all services\n"; -echo "- Any field with existing file path automatically uploaded via multipart\n"; -echo "- Works with any field name (logo, image, document, attachment, etc.)\n"; -echo "- POST: Automatically uses multipart/form-data when files detected\n"; -echo "- PUT: Automatically uses POST + _method=PUT when files detected\n"; -echo "- No client-side validation - API handles all parameter validation\n"; -echo "- File detection: Non-URL strings that point to existing files\n"; -echo "- Universal: Same logic applies to all API endpoints with file support\n"; \ No newline at end of file +echo "\nInvoice Template API examples completed!\n"; \ No newline at end of file diff --git a/lib/FasterPay/HttpClient.php b/lib/FasterPay/HttpClient.php index a52fa65..73584ec 100644 --- a/lib/FasterPay/HttpClient.php +++ b/lib/FasterPay/HttpClient.php @@ -84,7 +84,18 @@ public function postMultipart($endpoint, array $params = [], array $headers = [] foreach ($files as $fieldName => $fileValue) { if (is_object($fileValue)) { - $postData[$fieldName] = $fileValue; + if ($fileValue instanceof \SplFileInfo) { + // Convert SplFileInfo to file path for HTTP compatibility + $filePath = $fileValue->getPathname(); + if (class_exists('CURLFile')) { + $postData[$fieldName] = new \CURLFile($filePath); + } else { + $postData[$fieldName] = '@' . $filePath; + } + } else { + // Handle other file objects (CURLFile, etc.) + $postData[$fieldName] = $fileValue; + } } elseif (is_string($fileValue) && file_exists($fileValue)) { if (class_exists('CURLFile')) { $postData[$fieldName] = new \CURLFile($fileValue); @@ -119,19 +130,6 @@ private function buildPostData(array $data, array &$postData, $prefix) } } - private function buildPostData(array $data, array &$postData, $prefix) - { - foreach ($data as $key => $value) { - $currentKey = $prefix ? $prefix . '[' . $key . ']' : $key; - - if (is_array($value)) { - $this->buildPostData($value, $postData, $currentKey); - } else { - $postData[$currentKey] = $value; - } - } - } - private function extractFiles(array &$params) { $files = []; From 0831ce041b95730cf1b72264ba3bda343dfd523c Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 12:38:01 +0700 Subject: [PATCH 11/20] update --- code-samples/business/e-invoice/product.php | 353 ++++-------------- .../Services/Business/EInvoice/Product.php | 2 - 2 files changed, 72 insertions(+), 283 deletions(-) diff --git a/code-samples/business/e-invoice/product.php b/code-samples/business/e-invoice/product.php index c4d20fb..ac0a8f3 100644 --- a/code-samples/business/e-invoice/product.php +++ b/code-samples/business/e-invoice/product.php @@ -5,90 +5,43 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', + 'isTest' => 1, ]); -echo "FasterPay Invoice Product API Examples\n"; -echo "=======================================\n\n"; +echo "FasterPay E-Invoice Product API Examples\n"; +echo "=========================================\n\n"; -// Example 1: Create a new product -echo "1. Creating a new product\n"; -echo "-------------------------\n"; +// Example 1: Create product +echo "1. Creating product\n"; +echo "-------------------\n"; -$productData = [ - 'name' => 'Professional Website Package', - 'sku' => 'WEB-PRO-001', +$createData = [ + 'name' => 'Website Development Package', + 'sku' => 'WEB-DEV-001', 'type' => 'digital', - 'description' => 'Complete professional website package with responsive design and SEO optimization', + 'description' => 'Complete website development with modern responsive design.', 'prices' => [ [ 'price' => 2500.00, 'currency' => 'USD' - ], - [ - 'price' => 2100.00, - 'currency' => 'EUR' ] ] + // 'image' => '/path/to/product-image.jpg' // Uncomment for image upload (file path) + // 'image' => new SplFileInfo('/path/to/product-image.jpg') // Or use SplFileInfo object ]; try { - $productResponse = $businessGateway->invoiceProductService()->createProduct($productData); + $response = $businessGateway->eInvoiceProductService()->createProduct($createData); - if ($productResponse->isSuccessful()) { + if ($response->isSuccessful()) { echo "Product created successfully\n"; - $responseData = $productResponse->getDecodeResponse(); - $productId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-' . time(); - echo " Product ID: " . $productId . "\n"; - echo " SKU: " . $productData['sku'] . "\n"; - echo " Name: " . $productData['name'] . "\n"; - echo " Type: " . $productData['type'] . "\n"; - echo " Prices: " . count($productData['prices']) . " currencies\n"; - } else { - echo "Error: " . $productResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 2: Create product with image -echo "2. Creating product with image\n"; -echo "------------------------------\n"; - -$productWithImageData = [ - 'name' => 'Premium Software License', - 'sku' => 'SW-PREM-001', - 'type' => 'digital', - 'description' => 'Premium software license with full features and 1-year support', - 'prices' => [ - [ - 'price' => 299.99, - 'currency' => 'USD' - ] - ], - 'image' => '/path/to/product-image.jpg' // File path provided directly in params -]; - -try { - // Note: In real implementation, provide actual image file path in params['image'] - // The service automatically detects file fields and uses multipart upload - - // For demo purposes, create without image - $demoData = $productWithImageData; - unset($demoData['image']); // Remove for demo - $imageResponse = $businessGateway->invoiceProductService()->createProduct($demoData); - - if ($imageResponse->isSuccessful()) { - echo "Product with image created successfully\n"; - $responseData = $imageResponse->getDecodeResponse(); - $imageProductId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-IMG-' . time(); - echo " Product ID: " . $imageProductId . "\n"; - echo " Name: " . $productWithImageData['name'] . "\n"; - echo " Image: File would be uploaded automatically if 'image' field contains file path\n"; - echo " Usage: \$params['image'] = '/path/to/image.jpg'\n"; + $data = $response->getDecodeResponse(); + $productId = $data['data']['id'] ?: 'PD-' . time(); + echo " Product ID: $productId\n"; + echo " Name: {$createData['name']}\n"; + echo " Type: {$createData['type']}\n"; } else { - echo "Error: " . $imageResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -96,34 +49,24 @@ echo "\n"; -// Example 3: Get product details -echo "3. Getting product details\n"; +// Example 2: Get product details +echo "2. Getting product details\n"; echo "--------------------------\n"; -$productId = isset($productId) ? $productId : 'PD-' . time(); - try { - $detailsResponse = $businessGateway->invoiceProductService()->getProduct($productId); + $response = $businessGateway->eInvoiceProductService()->getProduct($productId); - if ($detailsResponse->isSuccessful()) { + if ($response->isSuccessful()) { echo "Product details retrieved\n"; - $details = $detailsResponse->getDecodeResponse(); - $product = isset($details['data']) ? $details['data'] : []; - - echo " ID: " . (isset($product['id']) ? $product['id'] : $productId) . "\n"; - echo " Name: " . (isset($product['name']) ? $product['name'] : 'N/A') . "\n"; - echo " SKU: " . (isset($product['sku']) ? $product['sku'] : 'N/A') . "\n"; - echo " Type: " . (isset($product['type']) ? $product['type'] : 'N/A') . "\n"; - echo " Description: " . substr(isset($product['description']) ? $product['description'] : 'N/A', 0, 50) . "...\n"; - - if (isset($product['prices']) && is_array($product['prices'])) { - echo " Prices:\n"; - foreach ($product['prices'] as $price) { - echo " - " . (isset($price['currency']) ? $price['currency'] : 'N/A') . ": " . (isset($price['price']) ? $price['price'] : '0.00') . "\n"; - } - } + $data = $response->getDecodeResponse(); + $product = $data['data'] ?: []; + + echo " ID: " . ($product['id'] ?: $productId) . "\n"; + echo " SKU: " . ($product['sku'] ?: 'N/A') . "\n"; + echo " Name: " . ($product['name'] ?: 'N/A') . "\n"; + echo " Type: " . ($product['type'] ?: 'N/A') . "\n"; } else { - echo "Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -131,34 +74,31 @@ echo "\n"; -// Example 4: Update product -echo "4. Updating product\n"; +// Example 3: Update product +echo "3. Updating product\n"; echo "-------------------\n"; $updateData = [ - 'name' => 'Updated Professional Website Package', - 'description' => 'Enhanced professional website package with advanced SEO optimization and mobile app integration', + 'name' => 'Website Development Package - Premium', + 'description' => 'Premium website development with enhanced features.', 'prices' => [ [ - 'price' => 2750.00, + 'price' => 3500.00, 'currency' => 'USD' - ], - [ - 'price' => 2300.00, - 'currency' => 'EUR' ] ] + // 'image' => '/path/to/updated-image.jpg' // Uncomment for image upload (file path) + // 'image' => new SplFileInfo('/path/to/updated-image.jpg') // Or use SplFileInfo object ]; try { - $updateResponse = $businessGateway->invoiceProductService()->updateProduct($productId, $updateData); + $response = $businessGateway->eInvoiceProductService()->updateProduct($productId, $updateData); - if ($updateResponse->isSuccessful()) { + if ($response->isSuccessful()) { echo "Product updated successfully\n"; - echo " Updated name and description\n"; - echo " Updated prices for USD and EUR\n"; + echo " Updated name and pricing\n"; } else { - echo "Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -166,33 +106,26 @@ echo "\n"; -// Example 5: List all products -echo "5. Listing all products\n"; -echo "-----------------------\n"; - -$listFilters = [ - 'page' => 1, - 'per_page' => 10 -]; +// Example 4: List products +echo "4. Listing products\n"; +echo "-------------------\n"; try { - $listResponse = $businessGateway->invoiceProductService()->listProducts($listFilters); - - if ($listResponse->isSuccessful()) { - echo "Products list retrieved\n"; - $listData = $listResponse->getDecodeResponse(); - $products = isset($listData['data']['data']) ? $listData['data']['data'] : []; + $response = $businessGateway->eInvoiceProductService()->listProducts(['limit' => 10, 'offset' => 0]); + if ($response->isSuccessful()) { + echo "Products retrieved successfully\n"; + $data = $response->getDecodeResponse(); + $products = $data['data'] ?: []; echo " Found " . count($products) . " products\n"; + foreach ($products as $product) { - $id = isset($product['id']) ? $product['id'] : 'Unknown'; - $name = isset($product['name']) ? $product['name'] : 'Unnamed'; - $sku = isset($product['sku']) ? $product['sku'] : 'No SKU'; - $type = isset($product['type']) ? $product['type'] : 'unknown'; - echo " - $name ($sku) - Type: $type - ID: $id\n"; + $id = $product['id'] ?: 'Unknown'; + $name = $product['name'] ?: 'Unnamed'; + echo " - $name ($id)\n"; } } else { - echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -200,70 +133,18 @@ echo "\n"; -// Example 6: Create multiple products (bulk operation) -echo "6. Creating multiple products (bulk operation)\n"; -echo "----------------------------------------------\n"; - -$bulkProducts = [ - [ - 'name' => 'Basic Hosting Plan', - 'sku' => 'HOST-BASIC-001', - 'type' => 'digital', - 'description' => 'Basic web hosting plan with 10GB storage', - 'prices' => [['price' => 9.99, 'currency' => 'USD']] - ], - [ - 'name' => 'Premium Hosting Plan', - 'sku' => 'HOST-PREM-001', - 'type' => 'digital', - 'description' => 'Premium web hosting plan with 100GB storage and SSL', - 'prices' => [['price' => 29.99, 'currency' => 'USD']] - ], - [ - 'name' => 'Physical Marketing Kit', - 'sku' => 'MKT-KIT-001', - 'type' => 'physical', - 'description' => 'Complete marketing kit with brochures and business cards', - 'prices' => [['price' => 149.99, 'currency' => 'USD']] - ] -]; - -foreach ($bulkProducts as $productData) { - try { - $response = $businessGateway->invoiceProductService()->createProduct($productData); - - if ($response->isSuccessful()) { - $responseData = $response->getDecodeResponse(); - $id = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-BULK-' . time(); - $price = $productData['prices'][0]['price']; - $currency = $productData['prices'][0]['currency']; - echo " Created: {$productData['name']} (SKU: {$productData['sku']}, Price: $price $currency)\n"; - } else { - echo " Error creating {$productData['name']}: " . $response->getErrors()->getMessage() . "\n"; - } - } catch (FasterPay\Exception $e) { - echo " Exception creating {$productData['name']}: " . $e->getMessage() . "\n"; - } -} - -echo "\n"; - -// Example 7: Delete price from product -echo "7. Deleting price from product\n"; -echo "------------------------------\n"; - -$productIdForPriceDeletion = isset($productId) ? $productId : 'PD-' . time(); -$currencyToDelete = 'EUR'; +// Example 5: Delete product price +echo "5. Deleting product price\n"; +echo "-------------------------\n"; try { - $deletePriceResponse = $businessGateway->invoiceProductService()->deleteProductPrice($productIdForPriceDeletion, $currencyToDelete); + $response = $businessGateway->eInvoiceProductService()->deleteProductPrice($productId, 'USD'); - if ($deletePriceResponse->isSuccessful()) { - echo "Price deleted successfully\n"; - echo " Product ID: " . $productIdForPriceDeletion . "\n"; - echo " Deleted Currency: " . $currencyToDelete . "\n"; + if ($response->isSuccessful()) { + echo "Product price deleted successfully\n"; + echo " Deleted USD price for Product ID: $productId\n"; } else { - echo "Error: " . $deletePriceResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; @@ -271,111 +152,21 @@ echo "\n"; -// Example 8: Create service products -echo "8. Creating service products\n"; -echo "----------------------------\n"; - -$serviceProducts = [ - [ - 'name' => 'Monthly Consultation Services', - 'sku' => 'CONSULT-MONTHLY', - 'type' => 'digital', - 'description' => 'Professional monthly consultation services including strategy planning and business analysis.', - 'prices' => [ - [ - 'price' => 500.00, - 'currency' => 'USD' - ] - ] - ], - [ - 'name' => 'Premium Support Package', - 'sku' => 'SUPPORT-PREMIUM', - 'type' => 'digital', - 'description' => '24/7 premium support with dedicated account manager and priority response.', - 'prices' => [ - [ - 'price' => 299.99, - 'currency' => 'USD' - ], - [ - 'price' => 249.99, - 'currency' => 'EUR' - ] - ] - ] -]; - -foreach ($serviceProducts as $serviceData) { - try { - $serviceResponse = $businessGateway->invoiceProductService()->createProduct($serviceData); - - if ($serviceResponse->isSuccessful()) { - $responseData = $serviceResponse->getDecodeResponse(); - $serviceId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'PD-SERVICE-' . time(); - $price = $serviceData['prices'][0]['price']; - $currency = $serviceData['prices'][0]['currency']; - - echo " Service product created: " . $serviceData['name'] . " (ID: " . $serviceId . ", Price: " . $price . " " . $currency . ")\n"; - } else { - echo " Error creating " . $serviceData['name'] . ": " . $serviceResponse->getErrors()->getMessage() . "\n"; - } - } catch (FasterPay\Exception $e) { - echo " Exception creating " . $serviceData['name'] . ": " . $e->getMessage() . "\n"; - } -} - -echo "\n"; - -// Example 10: Delete product -echo "10. Deleting product\n"; -echo "--------------------\n"; - -$productToDelete = 'PD-DELETE-' . time(); +// Example 6: Delete product +echo "6. Deleting product\n"; +echo "-------------------\n"; try { - $deleteResponse = $businessGateway->invoiceProductService()->deleteProduct($productToDelete); + $response = $businessGateway->eInvoiceProductService()->deleteProduct($productId); - if ($deleteResponse->isSuccessful()) { + if ($response->isSuccessful()) { echo "Product deleted successfully\n"; - echo " Deleted Product ID: " . $productToDelete . "\n"; + echo " Deleted Product ID: $productId\n"; } else { - echo "Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { echo "Exception: " . $e->getMessage() . "\n"; } -echo "\nInvoice Product API examples completed!\n"; -echo "Use cases:\n"; -echo "• Product catalog management\n"; -echo "• Multi-currency pricing\n"; -echo "• Digital product distribution\n"; -echo "• Physical inventory integration\n"; -echo "• Service offering management\n"; -echo "• SKU-based product lookup\n"; -echo "• Image upload and management\n"; -echo "• Price management by currency\n"; -echo "• Product type categorization\n"; -echo "• Bulk product operations\n"; - -echo "\nMultipart Support:\n"; -echo "• Automatic file detection in HttpClient\n"; -echo "• Image uploads supported for create and update\n"; -echo "• Uses multipart/form-data when image files present\n"; -echo "• POST method for create with automatic multipart\n"; -echo "• PUT method for update (converts to POST + _method=PUT for multipart)\n"; -echo "• Maximum image size: 1MB\n"; -echo "• Supported formats: JPG, PNG, GIF\n"; - -echo "\nProduct Types:\n"; -echo "• digital: Software, licenses, digital downloads\n"; -echo "• physical: Hardware, merchandise, shipped items\n"; - -echo "\nValidation Notes:\n"; -echo "• Only ID field validation implemented (as requested)\n"; -echo "• API handles all parameter validation server-side\n"; -echo "• Currency codes must be ISO-4217 format (3 characters)\n"; -echo "• Price amounts must be numeric and non-negative\n"; -echo "• Product names limited to 191 characters\n"; -echo "• SKU limited to 50 characters\n"; \ No newline at end of file +echo "\nE-Invoice Product API examples completed!\n"; \ No newline at end of file diff --git a/lib/FasterPay/Services/Business/EInvoice/Product.php b/lib/FasterPay/Services/Business/EInvoice/Product.php index aba162e..1d39a65 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Product.php +++ b/lib/FasterPay/Services/Business/EInvoice/Product.php @@ -21,7 +21,6 @@ public function createProduct(array $params = []) { $endpoint = $this->httpService->getEndPoint($this->endpoint); - // Use POST method - HttpClient will auto-detect files and use multipart if needed $response = $this->httpService->getHttpClient()->post($endpoint, $params); return new GeneralResponse($response); @@ -64,7 +63,6 @@ public function updateProduct($productId = '', array $params = []) $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $productId); - // Use PUT method - HttpClient will auto-detect files and use POST + _method=PUT if needed $response = $this->httpService->getHttpClient()->put($endpoint, $params); return new GeneralResponse($response); From 04bd44fd00c8f2e137fbd7f9c4e90ce66c75ff8a Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 12:40:15 +0700 Subject: [PATCH 12/20] update --- code-samples/business/e-invoice/product.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/code-samples/business/e-invoice/product.php b/code-samples/business/e-invoice/product.php index ac0a8f3..4356745 100644 --- a/code-samples/business/e-invoice/product.php +++ b/code-samples/business/e-invoice/product.php @@ -5,10 +5,9 @@ $businessGateway = new FasterPay\BusinessGateway([ 'publicKey' => '', 'privateKey' => '', - 'isTest' => 1, ]); -echo "FasterPay E-Invoice Product API Examples\n"; +echo "FasterPay Invoice Product API Examples\n"; echo "=========================================\n\n"; // Example 1: Create product @@ -31,7 +30,7 @@ ]; try { - $response = $businessGateway->eInvoiceProductService()->createProduct($createData); + $response = $businessGateway->invoiceProductService()->createProduct($createData); if ($response->isSuccessful()) { echo "Product created successfully\n"; @@ -54,7 +53,7 @@ echo "--------------------------\n"; try { - $response = $businessGateway->eInvoiceProductService()->getProduct($productId); + $response = $businessGateway->invoiceProductService()->getProduct($productId); if ($response->isSuccessful()) { echo "Product details retrieved\n"; @@ -92,7 +91,7 @@ ]; try { - $response = $businessGateway->eInvoiceProductService()->updateProduct($productId, $updateData); + $response = $businessGateway->invoiceProductService()->updateProduct($productId, $updateData); if ($response->isSuccessful()) { echo "Product updated successfully\n"; @@ -111,7 +110,7 @@ echo "-------------------\n"; try { - $response = $businessGateway->eInvoiceProductService()->listProducts(['limit' => 10, 'offset' => 0]); + $response = $businessGateway->invoiceProductService()->listProducts(['limit' => 10, 'offset' => 0]); if ($response->isSuccessful()) { echo "Products retrieved successfully\n"; @@ -138,7 +137,7 @@ echo "-------------------------\n"; try { - $response = $businessGateway->eInvoiceProductService()->deleteProductPrice($productId, 'USD'); + $response = $businessGateway->invoiceProductService()->deleteProductPrice($productId, 'USD'); if ($response->isSuccessful()) { echo "Product price deleted successfully\n"; @@ -157,7 +156,7 @@ echo "-------------------\n"; try { - $response = $businessGateway->eInvoiceProductService()->deleteProduct($productId); + $response = $businessGateway->invoiceProductService()->deleteProduct($productId); if ($response->isSuccessful()) { echo "Product deleted successfully\n"; @@ -169,4 +168,4 @@ echo "Exception: " . $e->getMessage() . "\n"; } -echo "\nE-Invoice Product API examples completed!\n"; \ No newline at end of file +echo "\nInvoice Product API examples completed!\n"; \ No newline at end of file From 640e60cf5631cf74ea717ffddcb55921b9021c63 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 13:43:46 +0700 Subject: [PATCH 13/20] update --- code-samples/business/e-invoice/invoice.php | 625 +++++++++++--------- 1 file changed, 348 insertions(+), 277 deletions(-) diff --git a/code-samples/business/e-invoice/invoice.php b/code-samples/business/e-invoice/invoice.php index 7bae378..0502981 100644 --- a/code-samples/business/e-invoice/invoice.php +++ b/code-samples/business/e-invoice/invoice.php @@ -1,22 +1,28 @@ '', - 'privateKey' => '', + 'publicKey' => 'your_public_key', + 'privateKey' => 'your_private_key', ]); -echo "FasterPay E-Invoice API Examples\n"; -echo "=================================\n\n"; +// Store component IDs for later use +$createdTemplateId = null; +$createdTaxId = null; +$createdDiscountId = null; +$createdProductId = null; +$createdContactId = null; + +// =================================================================== +// CREATE CONTACT FIRST +// =================================================================== $contactData = [ 'email' => 'john.smith@example.com', @@ -28,62 +34,239 @@ 'favorite' => true ]; -$contactResponse = $businessGateway->contactService()->createContact($contactData); +try { + $response = $businessGateway->contactService()->createContact($contactData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $createdContactId = $responseData['data']['id']; + echo 'Contact created: ' . $createdContactId . "\n"; + } else { + echo 'Error creating contact: ' . $response->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo 'Exception creating contact: ' . $e->getMessage() . "\n"; +} + +// =================================================================== +// CREATE TEMPLATE COMPONENT +// =================================================================== + +$templateData = [ + 'name' => 'Project Template', + 'footer' => 'Thank you for your business!', + 'colors' => [ + 'primary' => '#2563eb', + 'secondary' => '#f8fafc' + ], + 'localized_address' => [ + 'address_line1' => '123 Business Ave', + 'locality' => 'San Francisco', + 'administrative_area' => 'CA', + 'postal_code' => '94105' + ], + 'country_code' => 'US' + // 'logo' => new SplFileInfo('/path/to/logo.jpg') + // 'logo' => '/path/to/logo.jpg' +]; + +try { + $response = $businessGateway->invoiceTemplateService()->createTemplate($templateData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $createdTemplateId = $responseData['data']['id']; + echo 'Template created: ' . $createdTemplateId . "\n"; + } else { + echo 'Error creating template: ' . $response->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo 'Exception creating template: ' . $e->getMessage() . "\n"; +} + +// =================================================================== +// CREATE TAX COMPONENT +// =================================================================== + +$taxData = [ + 'name' => 'Sales Tax', + 'type' => 'percentage', + 'value' => 8.5, + 'description' => '8.5% sales tax for California' +]; + +try { + $response = $businessGateway->invoiceTaxService()->createTax($taxData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $createdTaxId = $responseData['data']['id']; + echo 'Tax created: ' . $createdTaxId . "\n"; + } else { + echo 'Error creating tax: ' . $response->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo 'Exception creating tax: ' . $e->getMessage() . "\n"; +} + +// =================================================================== +// CREATE DISCOUNT COMPONENT +// =================================================================== + +$discountData = [ + 'name' => 'Early Payment Discount', + 'type' => 'percentage', + 'value' => 10.0, + 'description' => '10% discount for early payment' +]; + +try { + $response = $businessGateway->invoiceDiscountService()->createDiscount($discountData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $createdDiscountId = $responseData['data']['id']; + echo 'Discount created: ' . $createdDiscountId . "\n"; + } else { + echo 'Error creating discount: ' . $response->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo 'Exception creating discount: ' . $e->getMessage() . "\n"; +} -$responseData = $contactResponse->getDecodeResponse(); -$contactId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'CT-' . time(); +// =================================================================== +// CREATE PRODUCT COMPONENT +// =================================================================== + +$productData = [ + 'name' => 'Website Development Package', + 'sku' => 'WEB-DEV-001', + 'type' => 'digital', + 'description' => 'Complete website development with responsive design.', + 'prices' => [ + [ + 'price' => 2500.00, + 'currency' => 'USD' + ] + ] + // 'image' => new SplFileInfo('/path/to/image.jpg') + // 'image' => '/path/to/image.jpg' +]; try { + $response = $businessGateway->invoiceProductService()->createProduct($productData); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $createdProductId = $responseData['data']['id']; + echo 'Product created: ' . $createdProductId . "\n"; + } else { + echo 'Error creating product: ' . $response->getErrors()->getMessage() . "\n"; + } +} catch (FasterPay\Exception $e) { + echo 'Exception creating product: ' . $e->getMessage() . "\n"; +} + +// =================================================================== +// CREATE INVOICE - Using Created Component IDs +// =================================================================== - // Example 1: Create invoice with embedded components - echo "1. Creating invoice with embedded components\n"; - echo "--------------------------------------------\n"; +$createdInvoiceId = null; - $invoiceData = [ +if ($createdTemplateId && $createdTaxId && $createdDiscountId && $createdProductId && $createdContactId) { + $invoiceDataWithIds = [ + 'invoice_template_id' => $createdTemplateId, + 'tax_id' => $createdTaxId, + 'discount_id' => $createdDiscountId, 'currency' => 'USD', - 'summary' => 'Website development project invoice', + 'summary' => 'Website development project using created components', 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => $contactId, + 'contact_id' => $createdContactId, 'due_date' => date('Y-m-d', strtotime('+30 days')), + 'items' => [ + [ + 'price' => 2500.00, + 'product_id' => $createdProductId, + 'tax_id' => $createdTaxId, + 'discount_id' => $createdDiscountId, + 'quantity' => 1 + ] + ] + ]; + + try { + $response = $businessGateway->invoiceService()->createInvoice($invoiceDataWithIds); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $createdInvoiceId = $responseData['data']['id']; + echo 'Invoice created with component IDs: ' . $createdInvoiceId . "\n"; + } else { + echo 'Error creating invoice: ' . $response->getErrors()->getMessage() . "\n"; + } + } catch (FasterPay\Exception $e) { + echo 'Exception creating invoice: ' . $e->getMessage() . "\n"; + } +} else { + echo "Cannot create invoice - missing required components\n"; +} + +// =================================================================== +// CREATE INVOICE - With Embedded Components (Alternative approach) +// =================================================================== + +$embeddedInvoiceId = null; + +if ($createdContactId) { + $invoiceDataWithEmbedded = [ 'template' => [ - 'name' => 'Project Template', - 'footer' => 'Thank you for your business!', + 'name' => 'Embedded Template', + 'footer' => 'Thank you for choosing our services!', 'colors' => [ - 'primary' => '#2563eb', - 'secondary' => '#f8fafc' + 'primary' => '#059669', + 'secondary' => '#f0fdf4' ], 'localized_address' => [ - 'address_line1' => '123 Business Ave', - 'locality' => 'San Francisco', + 'address_line1' => '456 Commerce St', + 'locality' => 'Los Angeles', 'administrative_area' => 'CA', - 'postal_code' => '94105' + 'postal_code' => '90210' ], 'country_code' => 'US' + // 'logo' => new SplFileInfo('/path/to/embedded-logo.jpg') + // 'logo' => '/path/to/embedded-logo.jpg' ], 'tax' => [ - 'name' => 'Sales Tax', - 'type' => 'flat', - 'value' => 0.08, - 'description' => '8% sales tax' + 'name' => 'State Sales Tax', + 'type' => 'percentage', + 'value' => 7.25, + 'description' => '7.25% California state sales tax' ], 'discount' => [ - 'name' => 'Early Payment Discount', - 'type' => 'percentage', - 'value' => 10.0, - 'description' => '10% discount for early payment' + 'name' => 'First Time Customer Discount', + 'type' => 'flat', + 'value' => 100.00, + 'currency' => 'USD', + 'description' => '$100 discount for first-time customers' ], + 'currency' => 'USD', + 'summary' => 'Website development with embedded components', + 'number' => 'INV-EMB-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), + 'contact_id' => $createdContactId, + 'due_date' => date('Y-m-d', strtotime('+45 days')), 'items' => [ [ - 'price' => 2500.00, - 'quantity' => 1, + 'price' => 3000.00, 'product' => [ - 'sku' => 'WEB-DEV-001', + 'sku' => 'WEB-DEV-PREMIUM', 'type' => 'digital', - 'name' => 'Website Development', - 'description' => 'Complete website development with responsive design', + 'name' => 'Premium Website Development', + 'description' => 'Premium website development with advanced features', + // 'image' => new SplFileInfo('/path/to/product-image.jpg') + // 'image' => '/path/to/product-image.jpg' 'prices' => [ [ - 'price' => 2500.00, + 'price' => 3000.00, 'currency' => 'USD' ] ] @@ -91,294 +274,182 @@ 'tax' => [ 'name' => 'Service Tax', 'type' => 'percentage', - 'value' => 5.0 - ] - ], - [ - 'price' => 99.99, - 'quantity' => 12, - 'product' => [ - 'sku' => 'HOST-PREM-001', - 'type' => 'digital', - 'name' => 'Premium Hosting', - 'description' => 'Premium hosting with SSL and backups' - ] + 'value' => 5.0, + 'description' => '5% service tax' + ], + 'discount' => [ + 'name' => 'Bulk Service Discount', + 'type' => 'percentage', + 'value' => 5.0, + 'description' => '5% discount for premium services' + ], + 'quantity' => 1 ] ] ]; - $response = $businessGateway->invoiceService()->createInvoice($invoiceData); - - if ($response->isSuccessful()) { - echo "✓ Invoice created successfully!\n"; - $data = $response->getDecodeResponse(); - $invoiceId = $data['data']['id']; - echo " Invoice ID: " . $invoiceId . "\n"; - echo " Invoice Number: " . $data['data']['number'] . "\n"; - echo " Status: " . $data['data']['status'] . "\n"; - echo " Currency: " . $data['data']['currency'] . "\n"; - echo " Items: " . count($data['data']['items']) . "\n\n"; - } else { - echo "✗ Failed to create invoice\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; + try { + $response = $businessGateway->invoiceService()->createInvoice($invoiceDataWithEmbedded); + + if ($response->isSuccessful()) { + $responseData = $response->getDecodeResponse(); + $embeddedInvoiceId = $responseData['data']['id']; + echo 'Invoice created with embedded components: ' . $embeddedInvoiceId . "\n"; + } else { + echo 'Error creating embedded invoice: ' . $response->getErrors()->getMessage() . "\n"; + } + } catch (FasterPay\Exception $e) { + echo 'Exception creating embedded invoice: ' . $e->getMessage() . "\n"; } +} - // Example 2: Create invoice using existing component IDs - echo "2. Creating invoice with existing component IDs\n"; - echo "-----------------------------------------------\n"; +// =================================================================== +// UPDATE INVOICE - Use Created Invoice ID +// =================================================================== - $simpleInvoiceData = [ - 'currency' => 'USD', - 'summary' => 'Consulting services invoice', - 'number' => 'INV-' . date('Y') . '-' . sprintf('%06d', rand(1, 999999)), - 'contact_id' => $contactId, - 'invoice_template_id' => 'IT-250527-AWRO', - 'tax_id' => 'TX-250527-2E9N', - 'discount_id' => 'DC-250527-WZX0', +if ($createdInvoiceId) { + $updateData = [ + 'summary' => 'Updated website development project', 'items' => [ [ - 'product_id' => 'PD-250528-L5CC', - 'price' => 150.00, - 'quantity' => 10, - 'tax_id' => 'TX-250527-2E9N' + 'price' => 2750.00, // Updated price + 'product_id' => $createdProductId, + 'tax_id' => $createdTaxId, + 'discount_id' => $createdDiscountId, + 'quantity' => 1 ] ] ]; - $response = $businessGateway->invoiceService()->createInvoice($simpleInvoiceData); - - if ($response->isSuccessful()) { - echo "✓ Simple invoice created successfully!\n"; - $data = $response->getDecodeResponse(); - $simpleInvoiceId = $data['data']['id']; - echo " Invoice ID: " . $simpleInvoiceId . "\n\n"; - } else { - echo "✗ Failed to create simple invoice\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; - } - - // Example 3: Get invoice details - echo "3. Getting invoice details\n"; - echo "--------------------------\n"; - - if (isset($invoiceId)) { - $response = $businessGateway->invoiceService()->getInvoice($invoiceId, ['include' => 'prices']); - + try { + $response = $businessGateway->invoiceService()->updateInvoice($createdInvoiceId, $updateData); + if ($response->isSuccessful()) { - $data = $response->getDecodeResponse(); - $invoice = $data['data']; - echo "✓ Invoice details retrieved successfully!\n"; - echo " ID: " . $invoice['id'] . "\n"; - echo " Status: " . $invoice['status'] . "\n"; - echo " Currency: " . $invoice['currency'] . "\n"; - echo " Summary: " . $invoice['summary'] . "\n"; - echo " Due Date: " . $invoice['due_date'] . "\n"; - echo " Items Count: " . count($invoice['items']) . "\n\n"; + echo 'Invoice updated successfully: ' . $createdInvoiceId . "\n"; } else { - echo "✗ Failed to get invoice details\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; + echo 'Error updating invoice: ' . $response->getErrors()->getMessage() . "\n"; } + } catch (FasterPay\Exception $e) { + echo 'Exception updating invoice: ' . $e->getMessage() . "\n"; } +} - // Example 4: List invoices with filters - echo "4. Listing invoices with filters\n"; - echo "--------------------------------\n"; +// =================================================================== +// LIST INVOICES +// =================================================================== - $filters = [ - 'limit' => 10, - 'offset' => 0, - 'status' => 'draft' - ]; +$filters = [ + 'limit' => 10, + 'offset' => 0, + 'status' => 'draft', + 'include' => 'items,items.product.prices' +]; +try { $response = $businessGateway->invoiceService()->listInvoices($filters); - + if ($response->isSuccessful()) { - echo "✓ Invoices listed successfully!\n"; - $data = $response->getDecodeResponse(); - $invoices = $data['data']['data']; - echo " Found " . count($invoices) . " draft invoices\n"; - - foreach (array_slice($invoices, 0, 3) as $invoice) { - echo " - " . $invoice['id'] . " (" . $invoice['status'] . ")\n"; + $responseData = $response->getDecodeResponse(); + $invoices = $responseData['data']['data']; + echo 'Found ' . count($invoices) . ' draft invoices' . "\n"; + + foreach ($invoices as $invoice) { + echo ' - Invoice ID: ' . $invoice['id'] . ' - Status: ' . $invoice['status'] . "\n"; } - echo "\n"; } else { - echo "✗ Failed to list invoices\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; + echo 'Error listing invoices: ' . $response->getErrors()->getMessage() . "\n"; } +} catch (FasterPay\Exception $e) { + echo 'Exception listing invoices: ' . $e->getMessage() . "\n"; +} - // Example 5: Update invoice details - echo "5. Updating invoice details\n"; - echo "---------------------------\n"; - - if (isset($invoiceId)) { - $updateData = [ - 'summary' => 'Updated website development project invoice', - 'template' => [ - 'footer' => 'Updated footer - Thank you for choosing our services!' - ] - ]; - - $response = $businessGateway->invoiceService()->updateInvoice($invoiceId, $updateData); +// =================================================================== +// GET INVOICE DETAILS - Use Created Invoice ID +// =================================================================== +if ($createdInvoiceId) { + try { + $response = $businessGateway->invoiceService()->getInvoice($createdInvoiceId); + if ($response->isSuccessful()) { - echo "✓ Invoice updated successfully!\n"; - echo " Updated summary and template footer\n\n"; + $responseData = $response->getDecodeResponse(); + $invoice = $responseData['data']; + echo 'Retrieved invoice details:' . "\n"; + echo ' ID: ' . $invoice['id'] . "\n"; + echo ' Status: ' . $invoice['status'] . "\n"; + echo ' Currency: ' . $invoice['currency'] . "\n"; + echo ' Summary: ' . $invoice['summary'] . "\n"; } else { - echo "✗ Failed to update invoice\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; + echo 'Error getting invoice details: ' . $response->getErrors()->getMessage() . "\n"; } + } catch (FasterPay\Exception $e) { + echo 'Exception getting invoice details: ' . $e->getMessage() . "\n"; } +} - // Example 6: Update invoice status - echo "6. Updating invoice status\n"; - echo "--------------------------\n"; - - if (isset($invoiceId)) { - $statusParams = [ - 'status' => 'sent', - 'notes' => 'Invoice sent to customer via email' - ]; +// =================================================================== +// UPDATE INVOICE STATUS - Use Created Invoice ID +// =================================================================== - $response = $businessGateway->invoiceService()->updateInvoiceStatus($invoiceId, $statusParams); +if ($createdInvoiceId) { + $statusData = [ + 'status' => 'sent' + ]; + try { + $response = $businessGateway->invoiceService()->updateInvoiceStatus($createdInvoiceId, $statusData); + if ($response->isSuccessful()) { - echo "✓ Invoice status updated successfully!\n"; - echo " New status: " . $statusParams['status'] . "\n"; - echo " Notes: " . $statusParams['notes'] . "\n\n"; + echo 'Invoice status updated to: ' . $statusData['status'] . ' for invoice: ' . $createdInvoiceId . "\n"; } else { - echo "✗ Failed to update invoice status\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; + echo 'Error updating invoice status: ' . $response->getErrors()->getMessage() . "\n"; } + } catch (FasterPay\Exception $e) { + echo 'Exception updating invoice status: ' . $e->getMessage() . "\n"; } +} - // Example 7: Preview invoice HTML - echo "7. Previewing invoice HTML\n"; - echo "--------------------------\n"; +// =================================================================== +// SEND INVOICE - Use Embedded Invoice ID +// =================================================================== - if (isset($invoiceId)) { - $response = $businessGateway->invoiceService()->previewInvoice($invoiceId); +if ($embeddedInvoiceId) { + $sendParams = [ + 'email' => 'customer@example.com' + ]; + try { + $response = $businessGateway->invoiceService()->sendInvoice($embeddedInvoiceId, $sendParams); + if ($response->isSuccessful()) { - echo "✓ Invoice preview generated successfully!\n"; - $htmlContent = $response->getRaw(); - echo " HTML content length: " . strlen($htmlContent) . " characters\n\n"; + echo 'Invoice sent successfully to: ' . $sendParams['email'] . ' for invoice: ' . $embeddedInvoiceId . "\n"; } else { - echo "✗ Failed to generate invoice preview\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; + echo 'Error sending invoice: ' . $response->getErrors()->getMessage() . "\n"; } + } catch (FasterPay\Exception $e) { + echo 'Exception sending invoice: ' . $e->getMessage() . "\n"; } +} - // Example 8: Download invoice PDF - echo "8. Downloading invoice PDF\n"; - echo "--------------------------\n"; - - if (isset($invoiceId)) { - $response = $businessGateway->invoiceService()->downloadInvoicePdf($invoiceId); +// =================================================================== +// DOWNLOAD INVOICE PDF - Use Created Invoice ID +// =================================================================== +if ($createdInvoiceId) { + try { + $response = $businessGateway->invoiceService()->downloadInvoicePdf($createdInvoiceId); + if ($response->isSuccessful()) { - echo "✓ Invoice PDF downloaded successfully!\n"; $pdfContent = $response->getRaw(); - echo " PDF size: " . strlen($pdfContent) . " bytes\n"; - - // Optionally save to file - // file_put_contents('invoice_' . $invoiceId . '.pdf', $pdfContent); - echo "\n"; + echo 'PDF downloaded successfully for: ' . $createdInvoiceId . "\n"; + echo 'PDF size: ' . strlen($pdfContent) . ' bytes' . "\n"; + + // Save to file if needed + // file_put_contents('invoice_' . $createdInvoiceId . '.pdf', $pdfContent); } else { - echo "✗ Failed to download invoice PDF\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; + echo 'Error downloading PDF: ' . $response->getErrors()->getMessage() . "\n"; } + } catch (FasterPay\Exception $e) { + echo 'Exception downloading PDF: ' . $e->getMessage() . "\n"; } - - // Example 9: Send invoice to customer - echo "9. Sending invoice to customer\n"; - echo "------------------------------\n"; - - if (isset($invoiceId)) { - // Send test email first - $response = $businessGateway->invoiceService()->sendInvoice($invoiceId, ['test' => true]); - - if ($response->isSuccessful()) { - echo "✓ Test invoice email sent successfully!\n"; - - // Send actual invoice - $response = $businessGateway->invoiceService()->sendInvoice($invoiceId); - - if ($response->isSuccessful()) { - echo "✓ Invoice sent to customer successfully!\n\n"; - } else { - echo "✗ Failed to send invoice to customer\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; - } - } else { - echo "✗ Failed to send test invoice\n"; - echo " Error: " . $response->getErrors()->getMessage() . "\n\n"; - } - } - - // Example 10: Delete operations (cleanup) - echo "10. Cleanup operations\n"; - echo "----------------------\n"; - - // Delete test invoice - $testInvoiceId = 'FPBIV-DELETE-' . time(); - $response = $businessGateway->invoiceService()->deleteInvoice($testInvoiceId); - - if ($response->isSuccessful()) { - echo "✓ Test invoice deleted successfully\n"; - } else { - echo "✓ Expected error for non-existent invoice (cleanup test)\n"; - } - - echo "\n"; - -} catch (FasterPay\Exception $e) { - echo "✗ An error occurred: " . $e->getMessage() . "\n"; - echo " Stack trace:\n" . $e->getTraceAsString() . "\n"; -} - -echo "\nE-Invoice API Examples Completed!\n"; -echo "==================================\n\n"; - -echo "Key Features Demonstrated:\n"; -echo "- Create invoices with embedded components (templates, products, taxes, discounts)\n"; -echo "- Create invoices using existing component IDs\n"; -echo "- Retrieve and list invoices with filtering\n"; -echo "- Update invoice details and status\n"; -echo "- Preview invoices and download PDFs\n"; -echo "- Send invoices to customers\n"; -echo "- Manage templates, products, taxes, and discounts\n"; -echo "- Handle webhook notifications\n"; -echo "- Comprehensive error handling\n"; -echo "- File upload support for multipart requests\n\n"; - -echo "Use Cases:\n"; -echo "• Automated billing and invoicing systems\n"; -echo "• Recurring subscription billing\n"; -echo "• Professional invoice generation\n"; -echo "• Payment tracking and reminders\n"; -echo "• Financial reporting and analytics\n"; -echo "• Multi-currency invoicing\n"; -echo "• Tax compliance and reporting\n"; -echo "• Customer payment portal integration\n"; -echo "• E-commerce order invoicing\n"; -echo "• Service-based business billing\n\n"; - -echo "Best Practices:\n"; -echo "- Validate only route parameters (IDs) - API handles all other parameter validation\n"; -echo "- Use BusinessGateway service methods for consistent architecture\n"; -echo "- Handle responses using isSuccessful(), getDecodeResponse(), and getErrors()\n"; -echo "- Use appropriate HTTP methods via HttpClient (post, get, put, delete)\n"; -echo "- Implement proper error handling and logging\n"; -echo "- Use webhook handlers for real-time status updates\n"; -echo "- Follow the documented invoice status lifecycle\n"; -echo "- Store component IDs for reuse and reference\n"; -echo "- Use test mode during development and integration\n"; -echo "- Implement retry logic for transient failures\n\n"; - -echo "Configuration Notes:\n"; -echo "- Set publicKey and privateKey to your actual FasterPay keys\n"; -echo "- Set isTest to 0 for production environment\n"; -echo "- Ensure contact_id references exist before creating invoices\n"; -echo "- Configure webhook URLs in your FasterPay dashboard\n"; -echo "- Test all operations in sandbox before going live\n"; \ No newline at end of file +} \ No newline at end of file From 1beff450fe4cc0b7f9dc1367475cdf77a655de2b Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 14:08:41 +0700 Subject: [PATCH 14/20] update --- code-samples/business/e-invoice/invoice.php | 90 ++++++++++------ code-samples/business/e-invoice/product.php | 6 +- code-samples/business/e-invoice/template.php | 4 +- lib/FasterPay/BusinessGateway.php | 3 +- lib/FasterPay/HttpClient.php | 26 ++--- .../Services/Business/EInvoice/Invoice.php | 102 +++++++++++------- 6 files changed, 141 insertions(+), 90 deletions(-) diff --git a/code-samples/business/e-invoice/invoice.php b/code-samples/business/e-invoice/invoice.php index 0502981..9dd6f86 100644 --- a/code-samples/business/e-invoice/invoice.php +++ b/code-samples/business/e-invoice/invoice.php @@ -1,7 +1,7 @@ contactService()->createContact($contactData); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $createdContactId = $responseData['data']['id']; @@ -72,7 +72,7 @@ try { $response = $businessGateway->invoiceTemplateService()->createTemplate($templateData); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $createdTemplateId = $responseData['data']['id']; @@ -97,7 +97,7 @@ try { $response = $businessGateway->invoiceTaxService()->createTax($taxData); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $createdTaxId = $responseData['data']['id']; @@ -122,7 +122,7 @@ try { $response = $businessGateway->invoiceDiscountService()->createDiscount($discountData); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $createdDiscountId = $responseData['data']['id']; @@ -155,7 +155,7 @@ try { $response = $businessGateway->invoiceProductService()->createProduct($productData); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $createdProductId = $responseData['data']['id']; @@ -171,6 +171,9 @@ // CREATE INVOICE - Using Created Component IDs // =================================================================== +echo "1. Creating invoice (non-embedded)\n"; +echo "-------------------\n"; + $createdInvoiceId = null; if ($createdTemplateId && $createdTaxId && $createdDiscountId && $createdProductId && $createdContactId) { @@ -196,7 +199,7 @@ try { $response = $businessGateway->invoiceService()->createInvoice($invoiceDataWithIds); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $createdInvoiceId = $responseData['data']['id']; @@ -215,6 +218,9 @@ // CREATE INVOICE - With Embedded Components (Alternative approach) // =================================================================== +echo "2. Creating invoice (embedded)\n"; +echo "-------------------\n"; + $embeddedInvoiceId = null; if ($createdContactId) { @@ -290,7 +296,7 @@ try { $response = $businessGateway->invoiceService()->createInvoice($invoiceDataWithEmbedded); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $embeddedInvoiceId = $responseData['data']['id']; @@ -307,6 +313,9 @@ // UPDATE INVOICE - Use Created Invoice ID // =================================================================== +echo "3. Updating invoice\n"; +echo "-------------------\n"; + if ($createdInvoiceId) { $updateData = [ 'summary' => 'Updated website development project', @@ -323,7 +332,7 @@ try { $response = $businessGateway->invoiceService()->updateInvoice($createdInvoiceId, $updateData); - + if ($response->isSuccessful()) { echo 'Invoice updated successfully: ' . $createdInvoiceId . "\n"; } else { @@ -338,6 +347,9 @@ // LIST INVOICES // =================================================================== +echo "4. Listing invoices\n"; +echo "-------------------\n"; + $filters = [ 'limit' => 10, 'offset' => 0, @@ -347,12 +359,12 @@ try { $response = $businessGateway->invoiceService()->listInvoices($filters); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $invoices = $responseData['data']['data']; echo 'Found ' . count($invoices) . ' draft invoices' . "\n"; - + foreach ($invoices as $invoice) { echo ' - Invoice ID: ' . $invoice['id'] . ' - Status: ' . $invoice['status'] . "\n"; } @@ -367,10 +379,13 @@ // GET INVOICE DETAILS - Use Created Invoice ID // =================================================================== +echo "5. Getting invoice details\n"; +echo "-------------------\n"; + if ($createdInvoiceId) { try { $response = $businessGateway->invoiceService()->getInvoice($createdInvoiceId); - + if ($response->isSuccessful()) { $responseData = $response->getDecodeResponse(); $invoice = $responseData['data']; @@ -388,46 +403,52 @@ } // =================================================================== -// UPDATE INVOICE STATUS - Use Created Invoice ID +// SEND INVOICE - Use Embedded Invoice ID // =================================================================== -if ($createdInvoiceId) { - $statusData = [ - 'status' => 'sent' +echo "6. Sending invoice\n"; +echo "-------------------\n"; + +if ($embeddedInvoiceId) { + $sendParams = [ + 'email' => 'customer@example.com' ]; try { - $response = $businessGateway->invoiceService()->updateInvoiceStatus($createdInvoiceId, $statusData); - + $response = $businessGateway->invoiceService()->sendInvoice($embeddedInvoiceId, $sendParams); + if ($response->isSuccessful()) { - echo 'Invoice status updated to: ' . $statusData['status'] . ' for invoice: ' . $createdInvoiceId . "\n"; + echo 'Invoice sent successfully to: ' . $sendParams['email'] . ' for invoice: ' . $embeddedInvoiceId . "\n"; } else { - echo 'Error updating invoice status: ' . $response->getErrors()->getMessage() . "\n"; + echo 'Error sending invoice: ' . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo 'Exception updating invoice status: ' . $e->getMessage() . "\n"; + echo 'Exception sending invoice: ' . $e->getMessage() . "\n"; } } // =================================================================== -// SEND INVOICE - Use Embedded Invoice ID +// UPDATE INVOICE STATUS - Use Created Invoice ID // =================================================================== -if ($embeddedInvoiceId) { - $sendParams = [ - 'email' => 'customer@example.com' +echo "7. Updating invoice status\n"; +echo "-------------------\n"; + +if ($createdInvoiceId) { + $statusData = [ + 'status' => 'void' ]; try { - $response = $businessGateway->invoiceService()->sendInvoice($embeddedInvoiceId, $sendParams); - + $response = $businessGateway->invoiceService()->updateInvoiceStatus($createdInvoiceId, $statusData); + if ($response->isSuccessful()) { - echo 'Invoice sent successfully to: ' . $sendParams['email'] . ' for invoice: ' . $embeddedInvoiceId . "\n"; + echo 'Invoice status updated to: ' . $statusData['status'] . ' for invoice: ' . $createdInvoiceId . "\n"; } else { - echo 'Error sending invoice: ' . $response->getErrors()->getMessage() . "\n"; + echo 'Error updating invoice status: ' . $response->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo 'Exception sending invoice: ' . $e->getMessage() . "\n"; + echo 'Exception updating invoice status: ' . $e->getMessage() . "\n"; } } @@ -435,15 +456,18 @@ // DOWNLOAD INVOICE PDF - Use Created Invoice ID // =================================================================== +echo "8. Downloading invoice PDF\n"; +echo "-------------------\n"; + if ($createdInvoiceId) { try { $response = $businessGateway->invoiceService()->downloadInvoicePdf($createdInvoiceId); - + if ($response->isSuccessful()) { - $pdfContent = $response->getRaw(); + $pdfContent = $response->getRawResponse(); echo 'PDF downloaded successfully for: ' . $createdInvoiceId . "\n"; echo 'PDF size: ' . strlen($pdfContent) . ' bytes' . "\n"; - + // Save to file if needed // file_put_contents('invoice_' . $createdInvoiceId . '.pdf', $pdfContent); } else { diff --git a/code-samples/business/e-invoice/product.php b/code-samples/business/e-invoice/product.php index 4356745..64bfdf6 100644 --- a/code-samples/business/e-invoice/product.php +++ b/code-samples/business/e-invoice/product.php @@ -59,7 +59,7 @@ echo "Product details retrieved\n"; $data = $response->getDecodeResponse(); $product = $data['data'] ?: []; - + echo " ID: " . ($product['id'] ?: $productId) . "\n"; echo " SKU: " . ($product['sku'] ?: 'N/A') . "\n"; echo " Name: " . ($product['name'] ?: 'N/A') . "\n"; @@ -115,9 +115,9 @@ if ($response->isSuccessful()) { echo "Products retrieved successfully\n"; $data = $response->getDecodeResponse(); - $products = $data['data'] ?: []; + $products = $data['data']['data'] ?: []; echo " Found " . count($products) . " products\n"; - + foreach ($products as $product) { $id = $product['id'] ?: 'Unknown'; $name = $product['name'] ?: 'Unnamed'; diff --git a/code-samples/business/e-invoice/template.php b/code-samples/business/e-invoice/template.php index 1803605..a7b88e5 100644 --- a/code-samples/business/e-invoice/template.php +++ b/code-samples/business/e-invoice/template.php @@ -90,7 +90,7 @@ echo "Template details retrieved\n"; $data = $response->getDecodeResponse(); $template = $data['data'] ?: []; - + echo " ID: " . ($template['id'] ?: $templateId) . "\n"; echo " Name: " . ($template['name'] ?: 'N/A') . "\n"; echo " Country: " . ($template['country_code'] ?: 'N/A') . "\n"; @@ -116,7 +116,7 @@ $data = $response->getDecodeResponse(); $templates = $data['data']['data'] ?: []; echo " Found " . count($templates) . " templates\n"; - + foreach ($templates as $template) { $id = $template['id'] ?: 'Unknown'; $name = $template['name'] ?: 'Unnamed'; diff --git a/lib/FasterPay/BusinessGateway.php b/lib/FasterPay/BusinessGateway.php index a43f551..96d13fa 100644 --- a/lib/FasterPay/BusinessGateway.php +++ b/lib/FasterPay/BusinessGateway.php @@ -17,7 +17,8 @@ class BusinessGateway implements GatewayInterface { - const BUSINESS_API_BASE_URL = 'https://business.fasterpay.com'; + const BUSINESS_API_BASE_URL = 'http://fp-ma.james.dang.linux04.php71'; +// const BUSINESS_API_BASE_URL = 'https://business.fasterpay.com'; protected $config; protected $http; diff --git a/lib/FasterPay/HttpClient.php b/lib/FasterPay/HttpClient.php index 73584ec..7a2ed46 100644 --- a/lib/FasterPay/HttpClient.php +++ b/lib/FasterPay/HttpClient.php @@ -37,11 +37,11 @@ public function post($endpoint, array $params = [], array $headers = []) { $testParams = $params; $files = $this->extractFiles($testParams); - + if (!empty($files)) { return $this->postMultipart($endpoint, $params, $headers); } - + return $this->call($endpoint, $params, 'POST', $headers); } @@ -49,12 +49,12 @@ public function put($endpoint, array $params = [], array $headers = []) { $testParams = $params; $files = $this->extractFiles($testParams); - + if (!empty($files)) { $params['_method'] = 'PUT'; return $this->postMultipart($endpoint, $params, $headers); } - + return $this->call($endpoint, $params, 'PUT', $headers); } @@ -68,18 +68,18 @@ public function postMultipart($endpoint, array $params = [], array $headers = [] $ch = $this->init(); $header = array_merge($this->header, $headers); - + $header = array_filter($header, function($h) { return stripos($h, 'Content-Type:') !== 0; }); - + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_URL, $endpoint); $files = $this->extractFiles($params); $postData = []; - + $this->buildPostData($params, $postData, ''); foreach ($files as $fieldName => $fileValue) { @@ -121,7 +121,7 @@ private function buildPostData(array $data, array &$postData, $prefix) { foreach ($data as $key => $value) { $currentKey = $prefix ? $prefix . '[' . $key . ']' : $key; - + if (is_array($value)) { $this->buildPostData($value, $postData, $currentKey); } else { @@ -141,7 +141,7 @@ private function extractFilesRecursive(array &$params, array &$files, $prefix) { foreach ($params as $key => $value) { $currentKey = $prefix ? $prefix . '[' . $key . ']' : $key; - + if (is_array($value)) { $this->extractFilesRecursive($params[$key], $files, $currentKey); } elseif ($this->isFileObject($value)) { @@ -154,10 +154,10 @@ private function extractFilesRecursive(array &$params, array &$files, $prefix) private function isFileObject($value) { if (is_object($value)) { - return $value instanceof \CURLFile || - (class_exists('SplFileInfo') && $value instanceof \SplFileInfo) || - (class_exists('finfo') && method_exists($value, 'getPathname')) || - method_exists($value, '__toString'); + return $value instanceof \CURLFile || + (class_exists('SplFileInfo') && $value instanceof \SplFileInfo) || + (class_exists('finfo') && method_exists($value, 'getPathname')) || + method_exists($value, '__toString'); } if (is_string($value) && !empty($value)) { diff --git a/lib/FasterPay/Services/Business/EInvoice/Invoice.php b/lib/FasterPay/Services/Business/EInvoice/Invoice.php index c50440b..c8f712e 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Invoice.php +++ b/lib/FasterPay/Services/Business/EInvoice/Invoice.php @@ -6,6 +6,13 @@ use FasterPay\Response\GeneralResponse; use FasterPay\Services\GeneralService; +/** + * FasterPay E-Invoice Service + * + * Main component service for handling FasterPay e-invoice operations + * Follows the same architecture as other business services + * Uses PHP 5.4+ latest syntax + */ class Invoice extends GeneralService { protected $endpoint = 'api/external/invoices'; @@ -19,10 +26,7 @@ class Invoice extends GeneralService public function createInvoice(array $params = []) { $endpoint = $this->httpService->getEndPoint($this->endpoint); - - // For multipart/form-data requests - $response = $this->httpService->getHttpClient()->postMultipart($endpoint, $params); - + $response = $this->httpService->getHttpClient()->post($endpoint, $params); return new GeneralResponse($response); } @@ -30,19 +34,31 @@ public function createInvoice(array $params = []) * Get e-invoice details * * @param string $invoiceId Invoice ID + * @param array $params Optional query parameters (include, etc.) * @return GeneralResponse * @throws Exception */ - public function getInvoice($invoiceId = '') + public function getInvoice($invoiceId = '', array $params = []) { if (empty($invoiceId)) { throw new Exception('Invoice ID is required'); } $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId); + $response = $this->httpService->getHttpClient()->get($endpoint, $params); + return new GeneralResponse($response); + } - $response = $this->httpService->getHttpClient()->get($endpoint); - + /** + * List invoices with optional filters + * + * @param array $filters Optional filters (limit, offset, status, etc.) + * @return GeneralResponse + */ + public function listInvoices(array $filters = []) + { + $endpoint = $this->httpService->getEndPoint($this->endpoint); + $response = $this->httpService->getHttpClient()->get($endpoint, $filters); return new GeneralResponse($response); } @@ -61,89 +77,99 @@ public function updateInvoice($invoiceId = '', array $params = []) } $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId); - - // Add _method=PUT for update via POST - $params['_method'] = 'PUT'; - - // For multipart/form-data requests - $response = $this->httpService->getHttpClient()->postMultipart($endpoint, $params); - + $response = $this->httpService->getHttpClient()->put($endpoint, $params); return new GeneralResponse($response); } /** - * Delete e-invoice + * Update invoice status * * @param string $invoiceId Invoice ID + * @param array $params Status parameters * @return GeneralResponse * @throws Exception */ - public function deleteInvoice($invoiceId = '') + public function updateInvoiceStatus($invoiceId = '', array $params = []) { if (empty($invoiceId)) { throw new Exception('Invoice ID is required'); } - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId); + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/status'); + $response = $this->httpService->getHttpClient()->put($endpoint, $params); + return new GeneralResponse($response); + } - $response = $this->httpService->getHttpClient()->delete($endpoint); + /** + * Preview invoice (get HTML) + * + * @param string $invoiceId Invoice ID + * @return GeneralResponse + * @throws Exception + */ + public function previewInvoice($invoiceId = '') + { + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/preview'); + $response = $this->httpService->getHttpClient()->get($endpoint); return new GeneralResponse($response); } /** - * List e-invoices + * Download invoice PDF * - * @param array $filters Optional filters + * @param string $invoiceId Invoice ID * @return GeneralResponse + * @throws Exception */ - public function listInvoices(array $filters = []) + public function downloadInvoicePdf($invoiceId = '') { - $endpoint = $this->httpService->getEndPoint($this->endpoint); - - $response = $this->httpService->getHttpClient()->get($endpoint, $filters); + if (empty($invoiceId)) { + throw new Exception('Invoice ID is required'); + } + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/pdf'); + $response = $this->httpService->getHttpClient()->get($endpoint); return new GeneralResponse($response); } /** - * Send e-invoice + * Send invoice to customer * * @param string $invoiceId Invoice ID - * @param array $sendParams Send parameters + * @param array $params Send parameters (test, etc.) * @return GeneralResponse * @throws Exception */ - public function sendInvoice($invoiceId = '', array $sendParams = []) + public function sendInvoice($invoiceId = '', array $params = []) { if (empty($invoiceId)) { throw new Exception('Invoice ID is required'); } $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/send'); - - $response = $this->httpService->getHttpClient()->post($endpoint, $sendParams); - + $response = $this->httpService->getHttpClient()->post($endpoint, $params); return new GeneralResponse($response); } /** - * Download e-invoice PDF + * Delete e-invoice * * @param string $invoiceId Invoice ID - * @param array $options Download options - * @return array Raw file response array with 'response' and 'httpCode' + * @return GeneralResponse * @throws Exception */ - public function downloadInvoicePdf($invoiceId = '', array $options = []) + public function deleteInvoice($invoiceId = '') { if (empty($invoiceId)) { throw new Exception('Invoice ID is required'); } - $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId . '/pdf'); - - // Return raw response for file download - return $this->httpService->getHttpClient()->get($endpoint, $options); + $endpoint = $this->httpService->getEndPoint($this->endpoint . '/' . $invoiceId); + $response = $this->httpService->getHttpClient()->delete($endpoint); + return new GeneralResponse($response); } } \ No newline at end of file From 03347fb87576f0618efa2cd5ecf923111a561fd8 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 14:34:13 +0700 Subject: [PATCH 15/20] update --- code-samples/business/contact.php | 93 +++++++++---------------------- 1 file changed, 26 insertions(+), 67 deletions(-) diff --git a/code-samples/business/contact.php b/code-samples/business/contact.php index 4962050..1a350dc 100644 --- a/code-samples/business/contact.php +++ b/code-samples/business/contact.php @@ -28,7 +28,7 @@ $contactResponse = $businessGateway->contactService()->createContact($contactData); if ($contactResponse->isSuccessful()) { - echo "✓ Contact created successfully\n"; + echo "Contact created successfully\n"; $responseData = $contactResponse->getDecodeResponse(); $contactId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'CT-' . time(); echo " Contact ID: " . $contactId . "\n"; @@ -37,16 +37,16 @@ echo " Phone: " . $contactData['phone'] . "\n"; echo " Country: " . $contactData['country'] . "\n"; } else { - echo "✗ Error: " . $contactResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $contactResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 2: Create another contact -echo "2. Creating another contact\n"; +// Example 2: Create another contact (for listing) +echo "2. Creating another contact (for listing)\n"; echo "---------------------------\n"; $secondContactData = [ @@ -63,7 +63,7 @@ $secondContactResponse = $businessGateway->contactService()->createContact($secondContactData); if ($secondContactResponse->isSuccessful()) { - echo "✓ Second contact created successfully\n"; + echo "Second contact created successfully\n"; $responseData = $secondContactResponse->getDecodeResponse(); $secondContactId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'CT-2-' . time(); echo " Contact ID: " . $secondContactId . "\n"; @@ -71,10 +71,10 @@ echo " Email: " . $secondContactData['email'] . "\n"; echo " Phone: " . $secondContactData['phone'] . "\n"; } else { - echo "✗ Error: " . $secondContactResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $secondContactResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -87,7 +87,7 @@ $detailsResponse = $businessGateway->contactService()->getContact($contactId); if ($detailsResponse->isSuccessful()) { - echo "✓ Contact details retrieved successfully\n"; + echo "Contact details retrieved successfully\n"; $details = $detailsResponse->getDecodeResponse(); if (isset($details['data'])) { @@ -99,10 +99,10 @@ echo " Country: " . (isset($contact['country']) ? $contact['country'] : 'N/A') . "\n"; } } else { - echo "✗ Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $detailsResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -122,56 +122,22 @@ $updateResponse = $businessGateway->contactService()->updateContact($contactId, $updateData); if ($updateResponse->isSuccessful()) { - echo "✓ Contact updated successfully\n"; + echo "Contact updated successfully\n"; echo " Contact ID: " . $contactId . "\n"; echo " New phone: " . $updateData['phone'] . "\n"; echo " Updated name: " . $updateData['first_name'] . "\n"; echo " Favorite: " . ($updateData['favorite'] ? 'Yes' : 'No') . "\n"; } else { - echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 5: Create another contact for listing -echo "5. Creating a third contact for demonstration\n"; -echo "---------------------------------------------\n"; - -$thirdContactData = [ - 'email' => 'mike.wilson@example.com', - 'phone' => '2015550555', - 'phone_country_code' => 'US', - 'first_name' => 'Mike', - 'last_name' => 'Wilson', - 'country' => 'US', - 'favorite' => true -]; - -try { - $thirdContactResponse = $businessGateway->contactService()->createContact($thirdContactData); - - if ($thirdContactResponse->isSuccessful()) { - echo "✓ Third contact created successfully\n"; - $responseData = $thirdContactResponse->getDecodeResponse(); - $thirdContactId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'CT-3-' . time(); - echo " Contact ID: " . $thirdContactId . "\n"; - echo " Name: " . $thirdContactData['first_name'] . " " . $thirdContactData['last_name'] . "\n"; - echo " Email: " . $thirdContactData['email'] . "\n"; - echo " Favorite: " . ($thirdContactData['favorite'] ? 'Yes' : 'No') . "\n"; - } else { - echo "✗ Error: " . $thirdContactResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 6: List contacts with filters -echo "6. Listing contacts with filters\n"; +// Example 5: List contacts with filters +echo "5. Listing contacts with filters\n"; echo "--------------------------------\n"; $filters = [ @@ -183,7 +149,7 @@ $listResponse = $businessGateway->contactService()->listContacts($filters); if ($listResponse->isSuccessful()) { - echo "✓ Contact list retrieved successfully\n"; + echo "Contact list retrieved successfully\n"; echo " Limit: 25 contacts\n"; $listData = $listResponse->getDecodeResponse(); @@ -203,38 +169,31 @@ } } } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -// Example 7: Delete a contact -echo "7. Deleting a contact\n"; +// Example 6: Delete a contact +echo "6. Deleting a contact\n"; echo "---------------------\n"; -$contactToDelete = isset($thirdContactId) ? $thirdContactId : 'CT-DELETE-' . time(); +$contactToDelete = isset($secondContactId) ? $secondContactId : 'CT-DELETE-' . time(); try { $deleteResponse = $businessGateway->contactService()->deleteContact($contactToDelete); if ($deleteResponse->isSuccessful()) { - echo "✓ Contact deleted successfully\n"; + echo "Contact deleted successfully\n"; echo " Deleted Contact ID: " . $contactToDelete . "\n"; } else { - echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } -echo "\nContact API examples completed!\n"; -echo "Use cases:\n"; -echo "• Customer relationship management (CRM)\n"; -echo "• Contact database management\n"; -echo "• Lead tracking and nurturing\n"; -echo "• Customer support integration\n"; -echo "• Marketing campaign management\n"; -echo "• Sales pipeline management\n"; \ No newline at end of file +echo "\nContact API examples completed!\n"; \ No newline at end of file From 7d0141d9ed8478f2419ac39580f1aec67f436ced Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 15:08:47 +0700 Subject: [PATCH 16/20] update --- code-samples/business/contact.php | 16 +++++----------- code-samples/business/e-invoice/discount.php | 4 ++-- code-samples/business/e-invoice/invoice.php | 4 ++-- code-samples/business/e-invoice/product.php | 5 ++++- .../Services/Business/EInvoice/Invoice.php | 2 +- .../Services/Business/EInvoice/Product.php | 2 +- .../Services/Business/EInvoice/Template.php | 2 +- lib/FasterPay/Services/Business/Payout.php | 2 +- 8 files changed, 17 insertions(+), 20 deletions(-) diff --git a/code-samples/business/contact.php b/code-samples/business/contact.php index 1a350dc..2a967a6 100644 --- a/code-samples/business/contact.php +++ b/code-samples/business/contact.php @@ -141,8 +141,8 @@ echo "--------------------------------\n"; $filters = [ - 'limit' => 25, - 'offset' => 0 + 'per_page' => 20, + 'page' => 1 ]; try { @@ -150,23 +150,17 @@ if ($listResponse->isSuccessful()) { echo "Contact list retrieved successfully\n"; - echo " Limit: 25 contacts\n"; $listData = $listResponse->getDecodeResponse(); - if (isset($listData['data']) && is_array($listData['data'])) { - echo " Found " . count($listData['data']) . " contacts\n"; + if (isset($listData['data']['data']) && is_array($listData['data']['data'])) { + $contacts = $listData['data']['data']; + echo " Found " . count($contacts) . " contacts\n"; - // Display first few contacts - $contacts = array_slice($listData['data'], 0, 3); foreach ($contacts as $contact) { $name = (isset($contact['first_name']) ? $contact['first_name'] : '') . ' ' . (isset($contact['last_name']) ? $contact['last_name'] : ''); $email = isset($contact['email']) ? $contact['email'] : 'No email'; echo " - " . trim($name) . " (" . $email . ")\n"; } - - if (count($listData['data']) > 3) { - echo " ... and " . (count($listData['data']) - 3) . " more\n"; - } } } else { echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; diff --git a/code-samples/business/e-invoice/discount.php b/code-samples/business/e-invoice/discount.php index 0a74b8d..d888b39 100644 --- a/code-samples/business/e-invoice/discount.php +++ b/code-samples/business/e-invoice/discount.php @@ -172,8 +172,8 @@ echo "--------------------\n"; $filters = [ - 'limit' => 10, - 'offset' => 0 + 'per_page' => 20, + 'page' => 1 ]; try { diff --git a/code-samples/business/e-invoice/invoice.php b/code-samples/business/e-invoice/invoice.php index 9dd6f86..2280523 100644 --- a/code-samples/business/e-invoice/invoice.php +++ b/code-samples/business/e-invoice/invoice.php @@ -351,8 +351,8 @@ echo "-------------------\n"; $filters = [ - 'limit' => 10, - 'offset' => 0, + 'per_page' => 20, + 'page' => 1 'status' => 'draft', 'include' => 'items,items.product.prices' ]; diff --git a/code-samples/business/e-invoice/product.php b/code-samples/business/e-invoice/product.php index 64bfdf6..f60028e 100644 --- a/code-samples/business/e-invoice/product.php +++ b/code-samples/business/e-invoice/product.php @@ -110,7 +110,10 @@ echo "-------------------\n"; try { - $response = $businessGateway->invoiceProductService()->listProducts(['limit' => 10, 'offset' => 0]); + $response = $businessGateway->invoiceProductService()->listProducts([ + 'per_page' => 20, + 'page' => 1 + ]); if ($response->isSuccessful()) { echo "Products retrieved successfully\n"; diff --git a/lib/FasterPay/Services/Business/EInvoice/Invoice.php b/lib/FasterPay/Services/Business/EInvoice/Invoice.php index c8f712e..50dd3b5 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Invoice.php +++ b/lib/FasterPay/Services/Business/EInvoice/Invoice.php @@ -52,7 +52,7 @@ public function getInvoice($invoiceId = '', array $params = []) /** * List invoices with optional filters * - * @param array $filters Optional filters (limit, offset, status, etc.) + * @param array $filters Optional filters * @return GeneralResponse */ public function listInvoices(array $filters = []) diff --git a/lib/FasterPay/Services/Business/EInvoice/Product.php b/lib/FasterPay/Services/Business/EInvoice/Product.php index 1d39a65..73192ba 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Product.php +++ b/lib/FasterPay/Services/Business/EInvoice/Product.php @@ -91,7 +91,7 @@ public function deleteProduct($productId = '') /** * List products with optional filters * - * @param array $filters Optional filters (limit, offset, sku, type, etc.) + * @param array $filters Optional filters * @return GeneralResponse */ public function listProducts(array $filters = []) diff --git a/lib/FasterPay/Services/Business/EInvoice/Template.php b/lib/FasterPay/Services/Business/EInvoice/Template.php index 7672394..7c1043a 100644 --- a/lib/FasterPay/Services/Business/EInvoice/Template.php +++ b/lib/FasterPay/Services/Business/EInvoice/Template.php @@ -86,7 +86,7 @@ public function deleteTemplate($templateId = '') /** * List templates * - * @param array $filters Optional filters (page, per_page, filter) + * @param array $filters Optional filters * @return GeneralResponse */ public function listTemplates(array $filters = []) diff --git a/lib/FasterPay/Services/Business/Payout.php b/lib/FasterPay/Services/Business/Payout.php index 03c97dd..ddd8274 100644 --- a/lib/FasterPay/Services/Business/Payout.php +++ b/lib/FasterPay/Services/Business/Payout.php @@ -48,7 +48,7 @@ public function getPayoutDetails($payoutId = '') /** * Get payout list * - * @param array $filters Optional filters (limit, offset, status, etc.) + * @param array $filters Optional filters * @return JsonResponse */ public function getPayoutList(array $filters = []) From 841c0b20ade8c1a63dfc09c6f6c529a09d10db27 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 7 Aug 2025 15:19:37 +0700 Subject: [PATCH 17/20] update --- code-samples/business/e-invoice/discount.php | 53 ++++----- code-samples/business/e-invoice/tax.php | 112 +++---------------- 2 files changed, 35 insertions(+), 130 deletions(-) diff --git a/code-samples/business/e-invoice/discount.php b/code-samples/business/e-invoice/discount.php index d888b39..6572b6b 100644 --- a/code-samples/business/e-invoice/discount.php +++ b/code-samples/business/e-invoice/discount.php @@ -26,7 +26,7 @@ $discountResponse = $businessGateway->invoiceDiscountService()->createDiscount($flatDiscountData); if ($discountResponse->isSuccessful()) { - echo "✓ Flat discount created successfully\n"; + echo "Flat discount created successfully\n"; $responseData = $discountResponse->getDecodeResponse(); $discountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-' . time(); echo " Discount ID: " . $discountId . "\n"; @@ -35,10 +35,10 @@ echo " Value: $" . number_format($flatDiscountData['value'], 2) . " " . $flatDiscountData['currency'] . "\n"; echo " Description: " . $flatDiscountData['description'] . "\n"; } else { - echo "✗ Error: " . $discountResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $discountResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -58,7 +58,7 @@ $volumeResponse = $businessGateway->invoiceDiscountService()->createDiscount($percentageDiscountData); if ($volumeResponse->isSuccessful()) { - echo "✓ Percentage discount created successfully\n"; + echo "Percentage discount created successfully\n"; $responseData = $volumeResponse->getDecodeResponse(); $volumeDiscountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-VOLUME-' . time(); echo " Discount ID: " . $volumeDiscountId . "\n"; @@ -67,10 +67,10 @@ echo " Value: " . $percentageDiscountData['value'] . "%\n"; echo " Description: " . $percentageDiscountData['description'] . "\n"; } else { - echo "✗ Error: " . $volumeResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $volumeResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -90,7 +90,7 @@ $loyaltyResponse = $businessGateway->invoiceDiscountService()->createDiscount($loyaltyDiscountData); if ($loyaltyResponse->isSuccessful()) { - echo "✓ Loyalty discount created successfully\n"; + echo "Loyalty discount created successfully\n"; $responseData = $loyaltyResponse->getDecodeResponse(); $loyaltyDiscountId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'DC-LOYALTY-' . time(); echo " Discount ID: " . $loyaltyDiscountId . "\n"; @@ -99,10 +99,10 @@ echo " Value: " . $loyaltyDiscountData['value'] . "%\n"; echo " Description: " . $loyaltyDiscountData['description'] . "\n"; } else { - echo "✗ Error: " . $loyaltyResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $loyaltyResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -117,7 +117,7 @@ $getDiscountResponse = $businessGateway->invoiceDiscountService()->getDiscount($testDiscountId); if ($getDiscountResponse->isSuccessful()) { - echo "✓ Discount details retrieved successfully\n"; + echo "Discount details retrieved successfully\n"; $discountData = $getDiscountResponse->getDecodeResponse(); if (isset($discountData['data'])) { $discount = $discountData['data']; @@ -131,10 +131,10 @@ echo " Description: " . (isset($discount['description']) ? $discount['description'] : 'N/A') . "\n"; } } else { - echo "✗ Error: " . $getDiscountResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $getDiscountResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -153,16 +153,16 @@ $updateResponse = $businessGateway->invoiceDiscountService()->updateDiscount($testDiscountId, $updateDiscountData); if ($updateResponse->isSuccessful()) { - echo "✓ Discount updated successfully\n"; + echo "Discount updated successfully\n"; echo " Discount ID: " . $testDiscountId . "\n"; echo " Updated Name: " . $updateDiscountData['name'] . "\n"; echo " Updated Value: $" . number_format($updateDiscountData['value'], 2) . "\n"; echo " Updated Description: " . $updateDiscountData['description'] . "\n"; } else { - echo "✗ Error: " . $updateResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $updateResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -180,7 +180,7 @@ $listResponse = $businessGateway->invoiceDiscountService()->listDiscounts($filters); if ($listResponse->isSuccessful()) { - echo "✓ Discount list retrieved successfully\n"; + echo "Discount list retrieved successfully\n"; $listData = $listResponse->getDecodeResponse(); if (isset($listData['data']['data']) && is_array($listData['data']['data'])) { echo " Found " . count($listData['data']['data']) . " discounts:\n"; @@ -194,10 +194,10 @@ } } } else { - echo "✗ Error: " . $listResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $listResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -212,24 +212,15 @@ $deleteResponse = $businessGateway->invoiceDiscountService()->deleteDiscount($deleteTestDiscountId); if ($deleteResponse->isSuccessful()) { - echo "✓ Discount deleted successfully\n"; + echo "Discount deleted successfully\n"; echo " Deleted Discount ID: " . $deleteTestDiscountId . "\n"; } else { - echo "✗ Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $deleteResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; -echo "\nInvoice Discount API examples completed!\n"; -echo "Use cases:\n"; -echo "• Early payment incentives\n"; -echo "• Volume purchase discounts\n"; -echo "• Loyalty customer rewards\n"; -echo "• Seasonal promotional offers\n"; -echo "• First-time customer discounts\n"; -echo "• Bulk order price reductions\n"; -echo "• Partner and affiliate discounts\n"; -echo "• Promotional campaign management\n"; \ No newline at end of file +echo "\nInvoice Discount API examples completed!\n"; \ No newline at end of file diff --git a/code-samples/business/e-invoice/tax.php b/code-samples/business/e-invoice/tax.php index 6e9a336..d2bf246 100644 --- a/code-samples/business/e-invoice/tax.php +++ b/code-samples/business/e-invoice/tax.php @@ -10,8 +10,8 @@ echo "FasterPay Invoice Tax API Examples\n"; echo "===================================\n\n"; -// Example 1: Create a basic percentage tax -echo "1. Creating a basic percentage tax\n"; +// Example 1: Create a tax +echo "1. Creating a tax\n"; echo "----------------------------------\n"; $taxData = [ @@ -42,71 +42,8 @@ echo "\n"; -// Example 2: Create a flat fee tax -echo "2. Creating a flat fee tax\n"; -echo "---------------------------\n"; - -$flatTaxData = [ - 'name' => 'Processing Fee', - 'type' => 'flat', - 'value' => 2.50, - 'currency' => 'USD', - 'description' => '$2.50 flat processing fee per transaction' -]; - -try { - $flatTaxResponse = $businessGateway->invoiceTaxService()->createTax($flatTaxData); - - if ($flatTaxResponse->isSuccessful()) { - echo "Flat tax created successfully\n"; - $responseData = $flatTaxResponse->getDecodeResponse(); - $flatTaxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-FLAT-' . time(); - echo " Tax ID: " . $flatTaxId . "\n"; - echo " Name: " . $flatTaxData['name'] . "\n"; - echo " Type: " . $flatTaxData['type'] . "\n"; - echo " Value: $" . $flatTaxData['value'] . " " . $flatTaxData['currency'] . "\n"; - } else { - echo "Error: " . $flatTaxResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 3: Create VAT tax -echo "3. Creating VAT tax\n"; -echo "-------------------\n"; - -$vatTaxData = [ - 'name' => 'VAT (UK)', - 'type' => 'percentage', - 'value' => 20.0, - 'description' => '20% VAT for United Kingdom transactions' -]; - -try { - $vatResponse = $businessGateway->invoiceTaxService()->createTax($vatTaxData); - - if ($vatResponse->isSuccessful()) { - echo "VAT tax created successfully\n"; - $responseData = $vatResponse->getDecodeResponse(); - $vatTaxId = isset($responseData['data']['id']) ? $responseData['data']['id'] : 'TX-VAT-' . time(); - echo " Tax ID: " . $vatTaxId . "\n"; - echo " Name: " . $vatTaxData['name'] . "\n"; - echo " Rate: " . $vatTaxData['value'] . "%\n"; - echo " Region: United Kingdom\n"; - } else { - echo "Error: " . $vatResponse->getErrors()->getMessage() . "\n"; - } -} catch (FasterPay\Exception $e) { - echo "Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 4: Get tax details -echo "4. Getting tax details\n"; +// Example 2: Get tax details +echo "2. Getting tax details\n"; echo "----------------------\n"; $taxId = isset($taxId) ? $taxId : 'TX-' . time(); @@ -134,8 +71,8 @@ echo "\n"; -// Example 5: Update tax -echo "5. Updating tax\n"; +// Example 3: Update tax +echo "3. Updating tax\n"; echo "---------------\n"; $updateData = [ @@ -160,8 +97,8 @@ echo "\n"; -// Example 6: List all taxes -echo "6. Listing all taxes\n"; +// Example 4: List all taxes +echo "4. Listing all taxes\n"; echo "--------------------\n"; $listFilters = [ @@ -194,8 +131,8 @@ echo "\n"; -// Example 7: Create multiple regional taxes -echo "7. Creating multiple regional taxes\n"; +// Example 5: Create multiple regional taxes +echo "5. Creating multiple regional taxes\n"; echo "-----------------------------------\n"; $regionalTaxes = [ @@ -237,8 +174,8 @@ echo "\n"; -// Example 8: Delete tax -echo "8. Deleting tax\n"; +// Example 6: Delete tax +echo "6. Deleting tax\n"; echo "----------------\n"; $deleteTaxId = isset($vatTaxId) ? $vatTaxId : 'TX-DELETE-' . time(); @@ -256,27 +193,4 @@ echo "Exception: " . $e->getMessage() . "\n"; } -echo "\nInvoice Tax API examples completed!\n"; -echo "Use cases:\n"; -echo "• Sales tax calculation and management\n"; -echo "• VAT handling for international transactions\n"; -echo "• Fixed processing fees\n"; -echo "• State and local tax compliance\n"; -echo "• Custom tax rates per region\n"; -echo "• Tax exemption handling\n"; -echo "• Multi-jurisdiction tax support\n"; -echo "• Automated tax calculation in invoices\n"; -echo "• Flat fee vs percentage tax options\n"; -echo "• Regional tax configuration\n"; - -echo "\nTax Types:\n"; -echo "• percentage: Tax calculated as percentage of amount\n"; -echo "• flat: Fixed tax amount regardless of invoice total\n"; - -echo "\nValidation Notes:\n"; -echo "• Only ID field validation implemented (as requested)\n"; -echo "• API handles all parameter validation server-side\n"; -echo "• Tax values for percentage type should be decimal (8.5 for 8.5%)\n"; -echo "• Tax values for flat type should be monetary amount\n"; -echo "• Currency required for flat type taxes\n"; -echo "• Tax names limited to 191 characters\n"; \ No newline at end of file +echo "\nInvoice Tax API examples completed!\n"; \ No newline at end of file From 0528b5b79eb7ddb49f584834bca718013665dbba Mon Sep 17 00:00:00 2001 From: James Date: Mon, 11 Aug 2025 10:30:24 +0700 Subject: [PATCH 18/20] restore base url --- lib/FasterPay/BusinessGateway.php | 3 +-- lib/FasterPay/Config.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/FasterPay/BusinessGateway.php b/lib/FasterPay/BusinessGateway.php index 96d13fa..a43f551 100644 --- a/lib/FasterPay/BusinessGateway.php +++ b/lib/FasterPay/BusinessGateway.php @@ -17,8 +17,7 @@ class BusinessGateway implements GatewayInterface { - const BUSINESS_API_BASE_URL = 'http://fp-ma.james.dang.linux04.php71'; -// const BUSINESS_API_BASE_URL = 'https://business.fasterpay.com'; + const BUSINESS_API_BASE_URL = 'https://business.fasterpay.com'; protected $config; protected $http; diff --git a/lib/FasterPay/Config.php b/lib/FasterPay/Config.php index 87267c1..e5c6d3e 100644 --- a/lib/FasterPay/Config.php +++ b/lib/FasterPay/Config.php @@ -5,7 +5,7 @@ class Config { const VERSION = '1.0.0'; - const API_BASE_URL = 'https://develop.pay2.fasterpay.bamboo.stuffio.com'; + const API_BASE_URL = 'https://pay.fasterpay.com'; const API_SANDBOX_BASE_URL = 'https://pay.sandbox.fasterpay.com'; private $publicKey = null; From dba8784149a89399b6c439a275ffc637f12fe575 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 11 Aug 2025 11:00:41 +0700 Subject: [PATCH 19/20] update address --- code-samples/business/address.php | 193 ++--------------- lib/FasterPay/Services/Business/Address.php | 218 -------------------- lib/FasterPay/Services/HttpService.php | 10 +- 3 files changed, 17 insertions(+), 404 deletions(-) diff --git a/code-samples/business/address.php b/code-samples/business/address.php index e1c2bc8..455ed8e 100644 --- a/code-samples/business/address.php +++ b/code-samples/business/address.php @@ -18,19 +18,19 @@ $addressFieldsResponse = $businessGateway->addressService()->getAddressFields('US'); if ($addressFieldsResponse->isSuccessful()) { - echo "✓ Address fields retrieved successfully\n"; + echo "Address fields retrieved successfully\n"; $data = $addressFieldsResponse->getDecodeResponse(); - $countryCode = $data['data']['country_code'] ?? 'US'; - $fields = $data['data']['fields'] ?? []; - $subdivisions = $data['data']['subdivisions'] ?? []; + $countryCode = isset($data['data']['country_code']) ? $data['data']['country_code'] : 'US'; + $fields = isset($data['data']['fields']) ? $data['data']['fields'] : []; + $subdivisions = isset($data['data']['subdivisions']) ? $data['data']['subdivisions'] : []; echo " Country: $countryCode\n"; echo " Required fields:\n"; foreach ($fields as $field) { - $type = $field['type'] ?? 'text'; - $label = $field['label'] ?? ''; - $name = $field['name'] ?? ''; + $type = isset($field['type']) ? $field['type'] : 'text'; + $label = isset($field['label']) ? $field['label'] : ''; + $name = isset($field['name']) ? $field['name'] : ''; echo " - $label ($name): $type\n"; } @@ -42,10 +42,10 @@ } echo "\n"; } else { - echo "✗ Error: " . $addressFieldsResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $addressFieldsResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; + echo "Exception: " . $e->getMessage() . "\n"; } echo "\n"; @@ -58,184 +58,19 @@ $canadaFieldsResponse = $businessGateway->addressService()->getAddressFields('CA'); if ($canadaFieldsResponse->isSuccessful()) { - echo "✓ Canadian address fields retrieved\n"; + echo "Canadian address fields retrieved\n"; $data = $canadaFieldsResponse->getDecodeResponse(); - $fields = $data['data']['fields'] ?? []; + $fields = isset($data['data']['fields']) ? $data['data']['fields'] : []; echo " Canada requires " . count($fields) . " fields:\n"; foreach ($fields as $field) { - echo " - " . ($field['label'] ?? 'Unknown') . "\n"; + echo " - " . (isset($field['label']) ? $field['label'] : 'Unknown') . "\n"; } } else { - echo "✗ Error: " . $canadaFieldsResponse->getErrors()->getMessage() . "\n"; + echo "Error: " . $canadaFieldsResponse->getErrors()->getMessage() . "\n"; } } catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 3: Get subdivisions for a country -echo "3. Getting subdivisions (states) for US\n"; -echo "---------------------------------------\n"; - -try { - $subdivisions = $businessGateway->addressService()->getSubdivisions('US'); - - if (!empty($subdivisions)) { - echo "✓ Found " . count($subdivisions) . " US states/territories\n"; - echo " Sample states:\n"; - - // Show first 10 states - $sampleStates = array_slice($subdivisions, 0, 10); - foreach ($sampleStates as $state) { - echo " - {$state['name']} ({$state['code']})\n"; - } - echo " ... and " . (count($subdivisions) - 10) . " more\n"; - } else { - echo "✗ No subdivisions found for US\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 4: Validate address data -echo "4. Validating address data\n"; -echo "--------------------------\n"; - -$sampleAddressData = [ - 'address_line1' => '123 Main Street', - 'locality' => 'New York', - 'administrative_area' => 'NY', - 'postal_code' => '10001' -]; - -try { - $validationResult = $businessGateway->addressService()->validateAddressData($sampleAddressData, 'US'); - - echo "✓ Address validation completed\n"; - echo " Valid: " . ($validationResult['valid'] ? 'Yes' : 'No') . "\n"; - echo " Country: {$validationResult['country_code']}\n"; - - if (!empty($validationResult['errors'])) { - echo " Errors:\n"; - foreach ($validationResult['errors'] as $error) { - echo " - $error\n"; - } - } - - if (!empty($validationResult['warnings'])) { - echo " Warnings:\n"; - foreach ($validationResult['warnings'] as $warning) { - echo " - $warning\n"; - } - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 5: Get address format for multiple countries -echo "5. Getting address formats for multiple countries\n"; -echo "-------------------------------------------------\n"; - -$countries = ['US', 'CA', 'GB', 'DE', 'FR']; - -try { - $addressFields = $businessGateway->addressService()->getMultipleAddressFields($countries); - - echo "✓ Retrieved address fields for multiple countries\n"; - - foreach ($countries as $country) { - if (isset($addressFields[$country])) { - if ($addressFields[$country]->isSuccessful()) { - $data = $addressFields[$country]->getDecodeResponse(); - $fieldCount = count($data['data']['fields'] ?? []); - $subdivisionCount = count($data['data']['subdivisions'] ?? []); - - echo " $country: $fieldCount fields"; - if ($subdivisionCount > 0) { - echo ", $subdivisionCount subdivisions"; - } - echo "\n"; - } else { - echo " $country: Error retrieving data\n"; - } - } else { - echo " $country: Failed to retrieve\n"; - } - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 6: Search for specific subdivision -echo "6. Searching for California\n"; -echo "---------------------------\n"; - -try { - $searchResults = $businessGateway->addressService()->searchSubdivisions('US', 'California'); - - if (!empty($searchResults)) { - echo "✓ Found " . count($searchResults) . " match(es) for 'California'\n"; - foreach ($searchResults as $result) { - echo " - {$result['name']} ({$result['code']})\n"; - } - } else { - echo "✗ No matches found for 'California'\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 7: Get specific subdivision by code -echo "7. Getting subdivision details for 'CA' (California)\n"; -echo "----------------------------------------------------\n"; - -try { - $subdivision = $businessGateway->addressService()->getSubdivisionByCode('US', 'CA'); - - if ($subdivision) { - echo "✓ Found subdivision details\n"; - echo " Code: {$subdivision['code']}\n"; - echo " Name: {$subdivision['name']}\n"; - echo " Has children: " . (empty($subdivision['children']) ? 'No' : 'Yes') . "\n"; - } else { - echo "✗ Subdivision 'CA' not found\n"; - } -} catch (FasterPay\Exception $e) { - echo "✗ Exception: " . $e->getMessage() . "\n"; -} - -echo "\n"; - -// Example 8: Check if country has subdivisions -echo "8. Checking subdivision support\n"; -echo "-------------------------------\n"; - -$testCountries = ['US', 'GB', 'MC']; // US, UK, Monaco - -foreach ($testCountries as $country) { - try { - $hasSubdivisions = $businessGateway->addressService()->hasSubdivisions($country); - echo " $country: " . ($hasSubdivisions ? 'Has subdivisions' : 'No subdivisions') . "\n"; - } catch (FasterPay\Exception $e) { - echo " $country: Error checking - " . $e->getMessage() . "\n"; - } + echo "Exception: " . $e->getMessage() . "\n"; } echo "\nAddress API examples completed!\n"; -echo "Use cases:\n"; -echo "• Dynamic address form generation\n"; -echo "• Address validation for different countries\n"; -echo "• State/province dropdown population\n"; -echo "• International shipping address collection\n"; -echo "• Address format compliance checking\n"; -echo "• Subdivision code lookup and validation\n"; diff --git a/lib/FasterPay/Services/Business/Address.php b/lib/FasterPay/Services/Business/Address.php index 49fc0ce..138870a 100644 --- a/lib/FasterPay/Services/Business/Address.php +++ b/lib/FasterPay/Services/Business/Address.php @@ -33,222 +33,4 @@ public function getAddressFields($countryCode = '') return new GeneralResponse($response); } - - /** - * Get supported address fields for multiple countries - * - * @param array $countryCodes Array of country codes - * @return array Array of GeneralResponse objects keyed by country code - * @throws Exception - */ - public function getMultipleAddressFields(array $countryCodes = []) - { - if (empty($countryCodes)) { - throw new Exception('At least one country code is required'); - } - - $responses = []; - - foreach ($countryCodes as $countryCode) { - try { - $responses[$countryCode] = $this->getAddressFields($countryCode); - } catch (Exception $e) { - // Log error but continue with other countries - error_log("Error getting address fields for $countryCode: " . $e->getMessage()); - $responses[$countryCode] = null; - } - } - - return $responses; - } - - /** - * Get subdivisions (states/provinces) for a country - * - * @param string $countryCode Country code (ISO 2-letter) - * @return array Array of subdivisions - * @throws Exception - */ - public function getSubdivisions($countryCode = '') - { - $fieldsResponse = $this->getAddressFields($countryCode); - - if ($fieldsResponse->isSuccessful()) { - $data = $fieldsResponse->getDecodeResponse(); - return $data['data']['subdivisions'] ?? []; - } - - return []; - } - - /** - * Get required fields for a country - * - * @param string $countryCode Country code (ISO 2-letter) - * @return array Array of required field definitions - * @throws Exception - */ - public function getRequiredFields($countryCode = '') - { - $fieldsResponse = $this->getAddressFields($countryCode); - - if ($fieldsResponse->isSuccessful()) { - $data = $fieldsResponse->getDecodeResponse(); - return $data['data']['fields'] ?? []; - } - - return []; - } - - /** - * Validate address data against country requirements - * - * @param array $addressData Address data to validate - * @param string $countryCode Country code for validation rules - * @return array Validation results - * @throws Exception - */ - public function validateAddressData(array $addressData = [], $countryCode = '') - { - if (empty($countryCode)) { - throw new Exception('Country code is required for validation'); - } - - $requiredFields = $this->getRequiredFields($countryCode); - $validationErrors = []; - $validationWarnings = []; - - foreach ($requiredFields as $field) { - $fieldName = $field['name'] ?? ''; - $fieldLabel = $field['label'] ?? $fieldName; - $fieldType = $field['type'] ?? 'text'; - - // Check if required field is present - if (empty($addressData[$fieldName])) { - $validationErrors[] = "$fieldLabel is required for $countryCode"; - continue; - } - - // Validate field type - switch ($fieldType) { - case 'select': - // For select fields, validate against subdivisions - if ($fieldName === 'administrative_area') { - $subdivisions = $this->getSubdivisions($countryCode); - $validCodes = array_column($subdivisions, 'code'); - - if (!in_array($addressData[$fieldName], $validCodes)) { - $validationErrors[] = "Invalid $fieldLabel for $countryCode"; - } - } - break; - - case 'text': - // Basic text validation - if (strlen($addressData[$fieldName]) < 2) { - $validationWarnings[] = "$fieldLabel seems too short"; - } - break; - } - } - - return [ - 'valid' => empty($validationErrors), - 'errors' => $validationErrors, - 'warnings' => $validationWarnings, - 'country_code' => $countryCode - ]; - } - - /** - * Get address format template for a country - * - * @param string $countryCode Country code (ISO 2-letter) - * @return array Address format information - * @throws Exception - */ - public function getAddressFormat($countryCode = '') - { - $fieldsResponse = $this->getAddressFields($countryCode); - - if ($fieldsResponse->isSuccessful()) { - $data = $fieldsResponse->getDecodeResponse(); - $fields = $data['data']['fields'] ?? []; - - return [ - 'country_code' => $countryCode, - 'fields' => $fields, - 'field_order' => array_column($fields, 'name'), - 'required_fields' => array_column($fields, 'name'), - 'subdivisions_available' => !empty($data['data']['subdivisions']) - ]; - } - - throw new Exception("Could not retrieve address format for $countryCode"); - } - - /** - * Check if a country supports subdivisions (states/provinces) - * - * @param string $countryCode Country code (ISO 2-letter) - * @return bool True if country has subdivisions - * @throws Exception - */ - public function hasSubdivisions($countryCode = '') - { - $subdivisions = $this->getSubdivisions($countryCode); - return !empty($subdivisions); - } - - /** - * Get subdivision by code - * - * @param string $countryCode Country code (ISO 2-letter) - * @param string $subdivisionCode Subdivision code - * @return array|null Subdivision information or null if not found - * @throws Exception - */ - public function getSubdivisionByCode($countryCode = '', $subdivisionCode = '') - { - if (empty($subdivisionCode)) { - throw new Exception('Subdivision code is required'); - } - - $subdivisions = $this->getSubdivisions($countryCode); - - foreach ($subdivisions as $subdivision) { - if ($subdivision['code'] === $subdivisionCode) { - return $subdivision; - } - } - - return null; - } - - /** - * Search subdivisions by name - * - * @param string $countryCode Country code (ISO 2-letter) - * @param string $searchTerm Search term - * @return array Array of matching subdivisions - * @throws Exception - */ - public function searchSubdivisions($countryCode = '', $searchTerm = '') - { - if (empty($searchTerm)) { - throw new Exception('Search term is required'); - } - - $subdivisions = $this->getSubdivisions($countryCode); - $matches = []; - - foreach ($subdivisions as $subdivision) { - if (stripos($subdivision['name'], $searchTerm) !== false || - stripos($subdivision['code'], $searchTerm) !== false) { - $matches[] = $subdivision; - } - } - - return $matches; - } } \ No newline at end of file diff --git a/lib/FasterPay/Services/HttpService.php b/lib/FasterPay/Services/HttpService.php index 7247a3a..65288df 100644 --- a/lib/FasterPay/Services/HttpService.php +++ b/lib/FasterPay/Services/HttpService.php @@ -2,20 +2,16 @@ namespace FasterPay\Services; -use FasterPay\BusinessGateway; -use FasterPay\Gateway; +use FasterPay\GatewayInterface; class HttpService implements HttpServiceInterface { /** - * @var Gateway|BusinessGateway + * @var GatewayInterface */ protected $client; - /** - * @param Gateway|BusinessGateway $client - */ - public function __construct($client) + public function __construct(GatewayInterface $client) { $this->client = $client; } From 97acf99028535902e31ad6bad73ab64244c53a0e Mon Sep 17 00:00:00 2001 From: James Date: Mon, 11 Aug 2025 11:42:04 +0700 Subject: [PATCH 20/20] support hash_equals for PHP 5.4 --- lib/autoload.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/autoload.php b/lib/autoload.php index b9908a1..d7ea526 100644 --- a/lib/autoload.php +++ b/lib/autoload.php @@ -7,6 +7,23 @@ throw new Exception('JSON PHP extension is required'); } +if (!function_exists('hash_equals')) { + function hash_equals($a, $b) { + echo 'strlen($a): ' . strlen($a); + echo 'strlen($b): ' . strlen($b); + if (strlen($a) !== strlen($b)) { + return false; + } + + $result = 0; + for ($i = 0; $i < strlen($a); $i++) { + $result |= ord($a[$i]) ^ ord($b[$i]); + } + echo $result === 0 ? 'YYEESSS' : 'NONONON'; + return $result === 0; + } +} + function autoload($className) { if (strpos($className, 'FasterPay') !== 0) {