Skip to content

Commit 9e890b1

Browse files
Merge pull request #46 from Potelo/feat-card-default
Add methods to manage credit cards for customers
2 parents 8ed25cc + c61e118 commit 9e890b1

14 files changed

Lines changed: 475 additions & 69 deletions

src/Contracts/CreditCardContract.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,18 @@ interface CreditCardContract
1919
* @throws GatewayException|GatewayNotAvailableException
2020
*/
2121
public function createCreditCard(CreditCard $creditCard): CreditCard;
22+
23+
/**
24+
* Get a credit card by its ID
25+
*
26+
* @throws GatewayException|GatewayNotAvailableException
27+
*/
28+
public function getCreditCard(CreditCard $creditCard): CreditCard;
29+
30+
/**
31+
* Delete a credit card
32+
*
33+
* @throws GatewayException|GatewayNotAvailableException
34+
*/
35+
public function deleteCreditCard(CreditCard $creditCard): void;
2236
}

src/Contracts/CustomerContract.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ public function createCustomer(Customer $customer): Customer;
2424
/**
2525
* Return one customer based on the customer ID
2626
*
27-
* @param string $id
28-
*
27+
* @param \Potelo\MultiPayment\Models\Customer $customer
2928
* @return Customer
30-
* @throws GatewayException|GatewayNotAvailableException
29+
* @throws \Potelo\MultiPayment\Exceptions\GatewayException
30+
* @throws \Potelo\MultiPayment\Exceptions\GatewayNotAvailableException
3131
*/
32-
public function getCustomer(string $id): Customer;
32+
public function getCustomer(Customer $customer): Customer;
3333

3434
/**
3535
* Update an existing customer
@@ -40,4 +40,13 @@ public function getCustomer(string $id): Customer;
4040
* @throws GatewayException|GatewayNotAvailableException
4141
*/
4242
public function updateCustomer(Customer $customer): Customer;
43+
44+
/**
45+
* Set the customer's default card
46+
*
47+
* @param \Potelo\MultiPayment\Models\Customer $customer
48+
* @param string $cardId
49+
* @return \Potelo\MultiPayment\Models\Customer
50+
*/
51+
public function setCustomerDefaultCard(Customer $customer, string $cardId): Customer;
4352
}

src/Contracts/InvoiceContract.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ public function createInvoice(Invoice $invoice): Invoice;
2424

2525
/**
2626
* Return one invoice based on the invoice ID
27-
*
28-
* @param string $id
29-
*
27+
*
28+
* @param \Potelo\MultiPayment\Models\Invoice $invoice
3029
* @return Invoice
31-
* @throws GatewayException|GatewayNotAvailableException
30+
* @throws \Potelo\MultiPayment\Exceptions\GatewayException
31+
* @throws \Potelo\MultiPayment\Exceptions\GatewayNotAvailableException
3232
*/
33-
public function getInvoice(string $id): Invoice;
33+
public function getInvoice(Invoice $invoice): Invoice;
3434

3535
/**
3636
* Refund an invoice

src/Exceptions/GatewayException.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ class GatewayException extends MultiPaymentException
1616
public function __construct(string $message = "", $errors = null)
1717
{
1818
$this->errors = $errors;
19-
parent::__construct($message . ' - ' . $this->parseErrorsToString($errors));
19+
$appends = $this->parseErrorsToString($errors);
20+
21+
if (!empty($appends)) {
22+
$message .= ' - ' . $appends;
23+
}
24+
25+
parent::__construct($message);
2026
}
2127

2228
/**

src/Facades/MultiPayment.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Potelo\MultiPayment\Facades;
44

55
use Illuminate\Support\Facades\Facade;
6+
use Potelo\MultiPayment\Models\CreditCard;
67
use Potelo\MultiPayment\Models\Invoice;
78
use Potelo\MultiPayment\Builders\InvoiceBuilder;
89
use Potelo\MultiPayment\Builders\CustomerBuilder;
@@ -14,8 +15,11 @@
1415
* @method static InvoiceBuilder newInvoice()
1516
* @method static CustomerBuilder newCustomer()
1617
* @method static CreditCardBuilder newCreditCard()
18+
* @method static CreditCard getCard(string $customerId, string $creditCardId)
19+
* @method static void deleteCard(string $customerId, string $creditCardId)
1720
* @method static \Potelo\MultiPayment\MultiPayment setGateway($gateway)
1821
* @method static Invoice chargeInvoiceWithCreditCard($invoice, ?string $creditCardToken = null, ?string $creditCardId = null)
22+
* @method static \Potelo\MultiPayment\Models\Customer setDefaultCard(string $customerId, string $creditCardId)
1923
*/
2024
class MultiPayment extends Facade
2125
{

src/Gateways/IuguGateway.php

Lines changed: 104 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -278,29 +278,16 @@ public function createCreditCard(CreditCard $creditCard): CreditCard
278278
throw new GatewayException('Error creating creditCard: ', $iuguCreditCard->errors);
279279
}
280280

281-
$creditCard->id = $iuguCreditCard->id ?? null;
282-
$creditCard->brand = $iuguCreditCard->data->brand ?? null;
283-
$creditCard->year = $iuguCreditCard->data->year ?? null;
284-
$creditCard->month = $iuguCreditCard->data->month ?? null;
285-
if (!empty($iuguCreditCard->data->holder_name)) {
286-
$names = explode(' ', $iuguCreditCard->data->holder_name);
287-
$creditCard->firstName = $names[0] ?? null;
288-
$creditCard->lastName = $names[array_key_last($names)] ?? null;
289-
}
290-
$creditCard->lastDigits = $iuguCreditCard->data->last_digits ?? substr($iuguCreditCard->data->display_number, -4);
291-
$creditCard->gateway = 'iugu';
292-
$creditCard->original = $iuguCreditCard;
293-
$creditCard->createdAt = new Carbon($iuguCreditCard->created_at_iso) ?? null;
294-
return $creditCard;
281+
return $this->parseIuguCard($iuguCreditCard, $creditCard);
295282
}
296283

297284
/**
298285
* @inheritDoc
299286
*/
300-
public function getInvoice(string $id): Invoice
287+
public function getInvoice(Invoice $invoice): Invoice
301288
{
302289
try {
303-
$iuguInvoice = \Iugu_Invoice::fetch($id);
290+
$iuguInvoice = \Iugu_Invoice::fetch($invoice->id);
304291
} catch (\IuguRequestException | IuguObjectNotFound $e) {
305292
if (str_contains($e->getMessage(), '502 Bad Gateway')) {
306293
throw new GatewayNotAvailableException($e->getMessage());
@@ -314,7 +301,7 @@ public function getInvoice(string $id): Invoice
314301
throw new GatewayException('Error getting invoice', $iuguInvoice->errors);
315302
}
316303

317-
return $this->parseInvoice($iuguInvoice);
304+
return $this->parseInvoice($iuguInvoice, $invoice);
318305
}
319306

320307
/**
@@ -587,10 +574,13 @@ private function chargeIuguInvoice(array $iuguInvoiceData)
587574
return $iuguCharge->invoice();
588575
}
589576

590-
public function getCustomer(string $id): Customer
577+
/**
578+
* @inheritDoc
579+
*/
580+
public function getCustomer(Customer $customer): Customer
591581
{
592582
try {
593-
$iuguCustomer = Iugu_Customer::fetch($id);
583+
$iuguCustomer = Iugu_Customer::fetch($customer->id);
594584
} catch (\IuguRequestException | IuguObjectNotFound $e) {
595585
if (str_contains($e->getMessage(), '502 Bad Gateway')) {
596586
throw new GatewayNotAvailableException($e->getMessage());
@@ -605,7 +595,7 @@ public function getCustomer(string $id): Customer
605595
throw new GatewayException('Error getting customer', $iuguCustomer->errors);
606596
}
607597

608-
return $this->parseCustomer($iuguCustomer);
598+
return $this->parseCustomer($iuguCustomer, $customer);
609599
}
610600

611601
public function updateCustomer(Customer $customer): Customer
@@ -747,6 +737,100 @@ private function customerToIuguData(Customer $customer): array
747737
}
748738
}
749739

740+
if (!empty($customer->defaultCard) && !empty($customer->defaultCard->id)) {
741+
$iuguCustomerData['default_payment_method_id'] = $customer->defaultCard->id;
742+
}
743+
750744
return $iuguCustomerData;
751745
}
746+
747+
/**
748+
* @inheritDoc
749+
*/
750+
public function setCustomerDefaultCard(Customer $customer, string $cardId): Customer
751+
{
752+
$customer->defaultCard = new CreditCard();
753+
$customer->defaultCard->id = $cardId;
754+
755+
return $this->updateCustomer($customer);
756+
}
757+
758+
/**
759+
* @inheritDoc
760+
*/
761+
public function deleteCreditCard(CreditCard $creditCard): void
762+
{
763+
try {
764+
$iuguCreditCard = new Iugu_PaymentMethod([
765+
'id' => $creditCard->id,
766+
'customer_id' => $creditCard->customer->id
767+
]);
768+
$iuguCreditCard->delete();
769+
} catch (\IuguRequestException | IuguObjectNotFound $e) {
770+
if (str_contains($e->getMessage(), '502 Bad Gateway')) {
771+
throw new GatewayNotAvailableException($e->getMessage());
772+
} else {
773+
throw new GatewayException($e->getMessage());
774+
}
775+
} catch (\IuguAuthenticationException $e) {
776+
throw new GatewayNotAvailableException($e->getMessage());
777+
} catch (\Exception $e) {
778+
throw new GatewayException($e->getMessage());
779+
}
780+
}
781+
782+
/**
783+
* @inheritDoc
784+
*/
785+
public function getCreditCard(CreditCard $creditCard): CreditCard
786+
{
787+
try {
788+
$iuguCustomer = new Iugu_Customer(['id' => $creditCard->customer->id]);
789+
$iuguCreditCard = $iuguCustomer->payment_methods()->fetch($creditCard->id);
790+
} catch (\IuguRequestException | IuguObjectNotFound $e) {
791+
if (str_contains($e->getMessage(), '502 Bad Gateway')) {
792+
throw new GatewayNotAvailableException($e->getMessage());
793+
} else {
794+
throw new GatewayException($e->getMessage());
795+
}
796+
} catch (\IuguAuthenticationException $e) {
797+
throw new GatewayNotAvailableException($e->getMessage());
798+
} catch (\Exception $e) {
799+
throw new GatewayException($e->getMessage());
800+
}
801+
if ($iuguCreditCard->errors) {
802+
throw new GatewayException('Error getting creditCard: ', $iuguCreditCard->errors);
803+
}
804+
805+
return $this->parseIuguCard($iuguCreditCard, $creditCard);
806+
}
807+
808+
/**
809+
* @param mixed $iuguCreditCard
810+
* @param \Potelo\MultiPayment\Models\CreditCard|null $creditCard
811+
* @return \Potelo\MultiPayment\Models\CreditCard
812+
*/
813+
private function parseIuguCard(mixed $iuguCreditCard, ?CreditCard $creditCard = null): CreditCard
814+
{
815+
if (is_null($creditCard)) {
816+
$creditCard = new CreditCard();
817+
}
818+
819+
$creditCard->id = $iuguCreditCard->id ?? null;
820+
$creditCard->brand = $iuguCreditCard->data->brand ?? null;
821+
$creditCard->year = $iuguCreditCard->data->year ?? null;
822+
$creditCard->month = $iuguCreditCard->data->month ?? null;
823+
$creditCard->description = $iuguCreditCard->description ?? null;
824+
825+
if (!empty($iuguCreditCard->data->holder_name)) {
826+
$names = explode(' ', $iuguCreditCard->data->holder_name);
827+
$creditCard->firstName = $names[0] ?? null;
828+
$creditCard->lastName = $names[array_key_last($names)] ?? null;
829+
}
830+
$creditCard->lastDigits = $iuguCreditCard->data->last_digits ?? substr($iuguCreditCard->data->display_number, -4);
831+
$creditCard->gateway = 'iugu';
832+
$creditCard->original = $iuguCreditCard;
833+
$creditCard->createdAt = new Carbon($iuguCreditCard->created_at_iso) ?? null;
834+
return $creditCard;
835+
}
752836
}

src/Models/Customer.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace Potelo\MultiPayment\Models;
44

55
use Carbon\Carbon;
6+
use Potelo\MultiPayment\Contracts\GatewayContract;
67
use Potelo\MultiPayment\Exceptions\ModelAttributeValidationException;
8+
use Potelo\MultiPayment\Helpers\ConfigurationHelper;
79

810
/**
911
* Class Customer
@@ -167,4 +169,51 @@ public function toArray(): array
167169
}
168170
return $array;
169171
}
172+
173+
public function setDefaultCard(string $cardId): Customer
174+
{
175+
$gateway = ConfigurationHelper::resolveGateway($this->gateway);
176+
return $gateway->setCustomerDefaultCard($this, $cardId);
177+
}
178+
179+
/**
180+
* Get a customer credit card by id from the gateway.
181+
*
182+
* @param string $creditCardId
183+
* @param string|GatewayContract|null $gateway
184+
*
185+
* @return static
186+
* @throws \Potelo\MultiPayment\Exceptions\ConfigurationException
187+
* @throws \Potelo\MultiPayment\Exceptions\GatewayException
188+
* @throws \Potelo\MultiPayment\Exceptions\GatewayNotAvailableException
189+
*/
190+
public function getCreditCard(string $creditCardId, GatewayContract|string $gateway = null): CreditCard
191+
{
192+
$gateway = ConfigurationHelper::resolveGateway($gateway);
193+
$creditCard = new CreditCard();
194+
$creditCard->customer = $this;
195+
$creditCard->id = $creditCardId;
196+
197+
return $gateway->getCreditCard($creditCard);
198+
}
199+
200+
/**
201+
* Delete a customer credit card by id from the gateway.
202+
*
203+
* @param string $creditCardId
204+
* @param \Potelo\MultiPayment\Contracts\GatewayContract|string|null $gateway
205+
* @return void
206+
* @throws \Potelo\MultiPayment\Exceptions\ConfigurationException
207+
* @throws \Potelo\MultiPayment\Exceptions\GatewayException
208+
* @throws \Potelo\MultiPayment\Exceptions\GatewayNotAvailableException
209+
*/
210+
public function deleteCreditCard(string $creditCardId, GatewayContract|string $gateway = null): void
211+
{
212+
$gateway = ConfigurationHelper::resolveGateway($gateway);
213+
$creditCard = new CreditCard();
214+
$creditCard->customer = $this;
215+
$creditCard->id = $creditCardId;
216+
217+
$gateway->deleteCreditCard($creditCard);
218+
}
170219
}

src/Models/Model.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,40 @@ protected static function getClassName(): string
161161
* @throws \Potelo\MultiPayment\Exceptions\ConfigurationException
162162
* @throws \Potelo\MultiPayment\Exceptions\GatewayException
163163
*/
164-
public static function get(string $id, GatewayContract|string $gateway = null): static
164+
public function get(GatewayContract|string $gateway = null): static
165165
{
166166
$method = 'get' . static::getClassName();
167167
$gateway = ConfigurationHelper::resolveGateway($gateway);
168168
if (!method_exists($gateway, $method)) {
169169
throw GatewayException::methodNotFound(get_class($gateway), $method);
170170
}
171-
return $gateway->$method($id);
171+
return $gateway->$method($this);
172+
}
173+
174+
/**
175+
* Delete the model instance by id in the gateway.
176+
*
177+
* @param \Potelo\MultiPayment\Contracts\GatewayContract|string|null $gateway
178+
* @return void
179+
* @throws \Potelo\MultiPayment\Exceptions\ConfigurationException
180+
* @throws \Potelo\MultiPayment\Exceptions\GatewayException
181+
*/
182+
public function delete(GatewayContract|string $gateway = null): void
183+
{
184+
$method = 'delete' . static::getClassName();
185+
$gateway = ConfigurationHelper::resolveGateway($gateway);
186+
if (!method_exists($gateway, $method)) {
187+
throw GatewayException::methodNotFound(get_class($gateway), $method);
188+
}
189+
$gateway->$method($this);
190+
}
191+
192+
/**
193+
* Refresh the model instance with the latest data from the gateway.
194+
*/
195+
public function refresh(GatewayContract|string $gateway = null): static
196+
{
197+
$gateway = ConfigurationHelper::resolveGateway($gateway);
198+
return $this->get($gateway);
172199
}
173200
}

0 commit comments

Comments
 (0)