diff --git a/app/Http/Controllers/CompanyGatewayController.php b/app/Http/Controllers/CompanyGatewayController.php index bdff0a8b1239..8d69b3738a1c 100644 --- a/app/Http/Controllers/CompanyGatewayController.php +++ b/app/Http/Controllers/CompanyGatewayController.php @@ -55,6 +55,9 @@ class CompanyGatewayController extends BaseController private string $checkout_key = '3758e7f7c6f4cecf0f4f348b9a00f456'; + private string $forte_key = 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs'; + + /** * CompanyGatewayController constructor. * @param CompanyRepository $company_repo @@ -228,6 +231,13 @@ class CompanyGatewayController extends BaseController StripeWebhook::dispatch($company_gateway->company->company_key, $company_gateway->id); } elseif($company_gateway->gateway_key == $this->checkout_key) { CheckoutSetupWebhook::dispatch($company_gateway->company->company_key, $company_gateway->id); + } elseif($company_gateway->gateway_key == $this->forte_key) { + + dispatch(function () use ($company_gateway) { + MultiDB::setDb($company_gateway->company->db); + $company_gateway->driver()->updateFees(); + })->afterResponse(); + } return $this->itemResponse($company_gateway); @@ -410,6 +420,13 @@ class CompanyGatewayController extends BaseController if($company_gateway->gateway_key == $this->checkout_key) { CheckoutSetupWebhook::dispatch($company_gateway->company->company_key, $company_gateway->fresh()->id); + }elseif($company_gateway->gateway_key == $this->forte_key){ + + dispatch(function () use ($company_gateway) { + MultiDB::setDb($company_gateway->company->db); + $company_gateway->driver()->updateFees(); + })->afterResponse(); + } return $this->itemResponse($company_gateway); diff --git a/app/PaymentDrivers/Factory/ForteCustomerFactory.php b/app/PaymentDrivers/Factory/ForteCustomerFactory.php index 1b127d58e7cf..eb6336d778fb 100644 --- a/app/PaymentDrivers/Factory/ForteCustomerFactory.php +++ b/app/PaymentDrivers/Factory/ForteCustomerFactory.php @@ -31,10 +31,11 @@ class ForteCustomerFactory 'phone' => $this->getBillingAddress($customer)['phone'], ] ], - 'currency_id' => $company->settings->currency_id, - - ])->merge($this->getBillingAddress($customer)) - ->merge($this->getShippingAddress($customer)) + 'settings' => [ + 'currency_id' => $company->settings->currency_id, + ], + ])->merge($this->getShippingAddress($customer)) + ->merge($this->getBillingAddress($customer)) ->toArray(); } @@ -101,12 +102,12 @@ class ForteCustomerFactory } return [ - 'address1' => $address['physical_address']['street_line1'], - 'address2' => $address['physical_address']['street_line2'], - 'city' => $address['physical_address']['locality'], - 'state' => $address['physical_address']['region'], - 'postal_code' => $address['physical_address']['postal_code'], - 'country_id' => '840', + 'shipping_address1' => $address['physical_address']['street_line1'], + 'shipping_address2' => $address['physical_address']['street_line2'], + 'shipping_city' => $address['physical_address']['locality'], + 'shipping_state' => $address['physical_address']['region'], + 'shipping_postal_code' => $address['physical_address']['postal_code'], + 'shipping_country_id' => '840', ]; } @@ -118,12 +119,14 @@ class ForteCustomerFactory $address = $customer['addresses'][1]; return [ - 'address1' => $address['physical_address']['street_line1'], - 'address2' => $address['physical_address']['street_line2'], - 'city' => $address['physical_address']['locality'], - 'state' => $address['physical_address']['region'], - 'postal_code' => $address['physical_address']['postal_code'], - 'country_id' => '840', + 'shipping_address1' => $address['physical_address']['street_line1'], + 'shipping_address2' => $address['physical_address']['street_line2'], + 'shipping_city' => $address['physical_address']['locality'], + 'shipping_state' => $address['physical_address']['region'], + 'shipping_postal_code' => $address['physical_address']['postal_code'], + 'shipping_country_id' => '840', + 'email' => $address['email'], + 'phone' => $address['phone'], ]; } diff --git a/app/PaymentDrivers/Factory/PaytraceCustomerFactory.php b/app/PaymentDrivers/Factory/PaytraceCustomerFactory.php new file mode 100644 index 000000000000..731a6c7085f6 --- /dev/null +++ b/app/PaymentDrivers/Factory/PaytraceCustomerFactory.php @@ -0,0 +1,59 @@ + $customer->billing_address->name ?? $customer->shipping_address->name, + 'contacts' => [ + [ + 'first_name' => $customer->billing_address->name ?? $customer->shipping_address->name, + 'last_name' => '', + 'email' => $customer->email, + 'phone' => $customer->phone, + ] + ], + 'currency_id' => $company->settings->currency_id, + 'address1' => $customer->billing_address->street_address, + 'address2' => $customer->billing_address->street_address2, + 'city' => $customer->billing_address->city, + 'state' => $customer->billing_address->state, + 'postal_code' => $customer->billing_address->zip, + 'country_id' => '840', + 'shipping_address1' => $customer->shipping_address->street_address, + 'shipping_address2' => $customer->shipping_address->street_address2, + 'shipping_city' => $customer->shipping_address->city, + 'shipping_state' => $customer->shipping_address->state, + 'shipping_postal_code' => $customer->shipping_address->zip, + 'shipping_country_id' => '840', + 'settings' => [ + 'currency_id' => $company->settings->currency_id, + ], + 'card' => [ + 'token' => $customer->customer_id, + 'last4' => $customer->credit_card->masked_number, + 'expiry_month' => $customer->credit_card->expiration_month, + 'expiry_year' => $customer->credit_card->expiration_year, + ], + ]) + ->toArray(); + + } + +} diff --git a/app/PaymentDrivers/Factory/SquareCustomerFactory.php b/app/PaymentDrivers/Factory/SquareCustomerFactory.php new file mode 100644 index 000000000000..fa3d9ad71bfd --- /dev/null +++ b/app/PaymentDrivers/Factory/SquareCustomerFactory.php @@ -0,0 +1,132 @@ +getCards() ?? [] as $card){ + + $meta = new \stdClass; + $meta->exp_month = $card->getExpMonth(); + $meta->exp_year = $card->getExpYear(); + $meta->last4 = $card->getLast4(); + $meta->brand = $card->getCardBrand(); + $meta->type = GatewayType::CREDIT_CARD; + + $cards[] = [ + 'token' => $card->getId(), + 'payment_meta' => $meta, + 'payment_method_id' => GatewayType::CREDIT_CARD, + 'gateway_customer_reference' => $customer->getId(), + ]; + } + + $address = $customer->getAddress(); + + return + collect([ + 'name' => $customer->getCompanyName() ?? ($customer->getGivenName() ?? '' ." " . $customer->getFamilyName() ?? ''), + 'contacts' => [ + [ + 'first_name' => $customer->getGivenName(), + 'last_name' => $customer->getFamilyName(), + 'email' => $customer->getEmailAddress(), + 'phone' => $customer->getPhoneNumber(), + ] + ], + 'currency_id' => $company->settings->currency_id, + 'address1' => $address->getAddressLine1(), + 'address2' => $address->getAddressLine2(), + 'city' => $address->getLocality(), + 'state' => $address->getAdministrativeDistrictLevel1(), + 'postal_code' => $address->getPostalCode(), + 'country_id' => '840', + 'settings' => [ + 'currency_id' => $company->settings->currency_id, + ], + 'cards' => $cards, + ]) + ->toArray(); + + } + +} diff --git a/app/PaymentDrivers/FortePaymentDriver.php b/app/PaymentDrivers/FortePaymentDriver.php index 5f6503af0e5f..0cbf1e3883df 100644 --- a/app/PaymentDrivers/FortePaymentDriver.php +++ b/app/PaymentDrivers/FortePaymentDriver.php @@ -253,6 +253,50 @@ class FortePaymentDriver extends BaseDriver ->first(); } + public function getLocation() + { + + $response = $this->stubRequest() + ->withQueryParameters(['page_size' => 10000]) + ->get("{$this->baseUri()}/organizations/{$this->getOrganisationId()}/locations/{$this->getLocationId()}"); + + if($response->successful()) + return $response->json(); + + return false; + } + + public function updateFees() + { + $response = $this->getLocation(); + + if($response) + { + $body = $response['services']; + + $fees_and_limits = $this->company_gateway->fees_and_limits; + + if($body['card']['service_fee_percentage'] > 0 || $body['card']['service_fee_additional_amount'] > 0){ + + $fees_and_limits->{1}->fee_amount = $body['card']['service_fee_additional_amount']; + $fees_and_limits->{1}->fee_percent = $body['card']['service_fee_percentage']; + } + + if($body['debit']['service_fee_percentage'] > 0 || $body['debit']['service_fee_additional_amount'] > 0) { + + $fees_and_limits->{2}->fee_amount = $body['debit']['service_fee_additional_amount']; + $fees_and_limits->{2}->fee_percent = $body['debit']['service_fee_percentage']; + } + + $this->company_gateway->fees_and_limits = $fees_and_limits; + $this->company_gateway->save(); + + } + + return false; + + } + public function importCustomers() { @@ -270,11 +314,12 @@ class FortePaymentDriver extends BaseDriver $data = $factory->convertToNinja($customer, $this->company_gateway->company); - if(strlen($customer['email']) == 0 || $this->getClient($customer['email'])) + if(strlen($data['email']) == 0 || $this->getClient($data['email'])) continue; $client_repo->save($data, ClientFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id)); + //persist any payment methods here! } } diff --git a/app/PaymentDrivers/PayPalPPCPPaymentDriver.php b/app/PaymentDrivers/PayPalPPCPPaymentDriver.php index 83ab1656ad11..5c86fae72acc 100644 --- a/app/PaymentDrivers/PayPalPPCPPaymentDriver.php +++ b/app/PaymentDrivers/PayPalPPCPPaymentDriver.php @@ -577,6 +577,11 @@ class PayPalPPCPPaymentDriver extends BaseDriver public function importCustomers() { + + // $response = $this->gatewayRequest('/v1/reporting/transactions', 'get', ['fields' => 'all','page_size' => 500,'start_date' => '2024-02-01T00:00:00-0000', 'end_date' => '2024-03-01T00:00:00-0000']); - } + // nlog($response->json()); + + return true; + } } diff --git a/app/PaymentDrivers/PayPalRestPaymentDriver.php b/app/PaymentDrivers/PayPalRestPaymentDriver.php index ae6d68e6f301..1d2bbd90bac3 100644 --- a/app/PaymentDrivers/PayPalRestPaymentDriver.php +++ b/app/PaymentDrivers/PayPalRestPaymentDriver.php @@ -424,7 +424,7 @@ class PayPalRestPaymentDriver extends BaseDriver SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_PAYPAL, $this->client, - $this->client->company, + $this->client->company ?? $this->company_gateway->company, ); throw new PaymentFailed("Gateway failure - {$r->body()}", 401); @@ -474,4 +474,10 @@ class PayPalRestPaymentDriver extends BaseDriver return false; } + + public function importCustomers() + { + return true; + } + } diff --git a/app/PaymentDrivers/PayTrace/CreditCard.php b/app/PaymentDrivers/PayTrace/CreditCard.php index 0fa5f37991d1..b08a27088d1e 100644 --- a/app/PaymentDrivers/PayTrace/CreditCard.php +++ b/app/PaymentDrivers/PayTrace/CreditCard.php @@ -59,6 +59,9 @@ class CreditCard 'enc_key' => $data['enc_key'], 'integrator_id' => $this->paytrace->company_gateway->getConfigField('integratorId'), 'billing_address' => $this->buildBillingAddress(), + 'email' => $this->paytrace->client->present()->email(), + 'phone' => $this->paytrace->client->present()->phone(), + ]; $response = $this->paytrace->gatewayRequest('/v1/customer/pt_protect_create', $post_data); diff --git a/app/PaymentDrivers/PaytracePaymentDriver.php b/app/PaymentDrivers/PaytracePaymentDriver.php index 2d262e105cae..05278300bc7c 100644 --- a/app/PaymentDrivers/PaytracePaymentDriver.php +++ b/app/PaymentDrivers/PaytracePaymentDriver.php @@ -11,19 +11,24 @@ namespace App\PaymentDrivers; -use App\Exceptions\SystemError; -use App\Http\Requests\Payments\PaymentWebhookRequest; -use App\Jobs\Util\SystemLogger; -use App\Models\ClientGatewayToken; -use App\Models\GatewayType; use App\Models\Invoice; use App\Models\Payment; +use App\Utils\CurlUtils; +use App\Models\SystemLog; +use App\Models\GatewayType; use App\Models\PaymentHash; use App\Models\PaymentType; -use App\Models\SystemLog; -use App\PaymentDrivers\PayTrace\CreditCard; -use App\Utils\CurlUtils; +use App\Factory\ClientFactory; +use App\Exceptions\SystemError; +use App\Jobs\Util\SystemLogger; use App\Utils\Traits\MakesHash; +use App\Models\ClientGatewayToken; +use App\Repositories\ClientRepository; +use App\PaymentDrivers\PayTrace\CreditCard; +use App\Repositories\ClientContactRepository; +use App\Http\Requests\Payments\PaymentWebhookRequest; +use App\Models\ClientContact; +use App\PaymentDrivers\Factory\PaytraceCustomerFactory; class PaytracePaymentDriver extends BaseDriver { @@ -260,4 +265,62 @@ class PaytracePaymentDriver extends BaseDriver return false; } + + public function importCustomers() + { + + $data = [ + 'integrator_id' => $this->company_gateway->getConfigField('integratorId'), + ]; + + $response = $this->gatewayRequest('/v1/customer/export', $data); + + nlog($response); + + if ($response && $response->success) { + + $client_repo = new ClientRepository(new ClientContactRepository()); + $factory = new PaytraceCustomerFactory(); + + foreach($response->customers as $customer) + { + $data = $factory->convertToNinja($customer, $this->company_gateway->company); + + $client = false; + + if(str_contains($data['contacts'][0]['email'], "@")) + { + $client = ClientContact::query() + ->where('company_id', $this->company_gateway->company_id) + ->where('email', $data['contacts'][0]['email']) + ->first()->client ?? false; + } + + if(!$client) + $client = $client_repo->save($data, ClientFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id)); + + $this->client = $client; + + if(ClientGatewayToken::query()->where('client_id', $client->id)->where('token',$data['card']['token'])->exists()) + continue; + + $cgt = []; + $cgt['token'] = $data['card']['token']; + $cgt['payment_method_id'] = GatewayType::CREDIT_CARD; + + $payment_meta = new \stdClass(); + $payment_meta->exp_month = $data['card']['expiry_month']; + $payment_meta->exp_year = $data['card']['expiry_year']; + $payment_meta->brand = 'CC'; + $payment_meta->last4 = $data['card']['last4']; + $payment_meta->type = GatewayType::CREDIT_CARD; + + $cgt['payment_meta'] = $payment_meta; + + $token = $this->storeGatewayToken($cgt, []); + + } + } + + } } diff --git a/app/PaymentDrivers/Square/CreditCard.php b/app/PaymentDrivers/Square/CreditCard.php index da53d36a2610..80b48fb5a15a 100644 --- a/app/PaymentDrivers/Square/CreditCard.php +++ b/app/PaymentDrivers/Square/CreditCard.php @@ -197,7 +197,7 @@ class CreditCard implements MethodInterface { $square_card = new \Square\Models\Card(); - $square_card->setCustomerId($this->findOrCreateClient()); + $square_card->setCustomerId($this->square_driver->findOrCreateClient()); $body = new \Square\Models\CreateCardRequest(uniqid("st", true), $source_id, $square_card); @@ -238,82 +238,5 @@ class CreditCard implements MethodInterface return false; } - private function findOrCreateClient() - { - $email_address = new \Square\Models\CustomerTextFilter(); - $email_address->setExact($this->square_driver->client->present()->email()); - - $filter = new \Square\Models\CustomerFilter(); - $filter->setEmailAddress($email_address); - - $query = new \Square\Models\CustomerQuery(); - $query->setFilter($filter); - - $body = new \Square\Models\SearchCustomersRequest(); - $body->setQuery($query); - - $api_response = $this->square_driver - ->init() - ->square - ->getCustomersApi() - ->searchCustomers($body); - - $customers = false; - - if ($api_response->isSuccess()) { - $customers = $api_response->getBody(); - $customers = json_decode($customers); - - if (count([$api_response->getBody(), 1]) == 0) { - $customers = false; - } - } else { - $errors = $api_response->getErrors(); - } - - if ($customers && property_exists($customers, 'customers')) { - return $customers->customers[0]->id; - } - - return $this->createClient(); - } - - private function createClient() - { - $country = $this->square_driver->client->country ? $this->square_driver->client->country->iso_3166_2 : $this->square_driver->client->company->country()->iso_3166_2; - - /* Step two - create the customer */ - $billing_address = new \Square\Models\Address(); - $billing_address->setAddressLine1($this->square_driver->client->address1); - $billing_address->setAddressLine2($this->square_driver->client->address2); - $billing_address->setLocality($this->square_driver->client->city); - $billing_address->setAdministrativeDistrictLevel1($this->square_driver->client->state); - $billing_address->setPostalCode($this->square_driver->client->postal_code); - $billing_address->setCountry($country); - - $body = new \Square\Models\CreateCustomerRequest(); - $body->setGivenName($this->square_driver->client->present()->name()); - $body->setFamilyName(''); - $body->setEmailAddress($this->square_driver->client->present()->email()); - $body->setAddress($billing_address); - // $body->setPhoneNumber($this->square_driver->client->phone); - $body->setReferenceId($this->square_driver->client->number); - $body->setNote('Created by Invoice Ninja.'); - - $api_response = $this->square_driver - ->init() - ->square - ->getCustomersApi() - ->createCustomer($body); - - if ($api_response->isSuccess()) { - $result = $api_response->getResult(); - - return $result->getCustomer()->getId(); - } else { - $errors = $api_response->getErrors(); - nlog($errors); - return $this->processUnsuccessfulPayment($api_response); - } - } + } diff --git a/app/PaymentDrivers/SquarePaymentDriver.php b/app/PaymentDrivers/SquarePaymentDriver.php index f0420f1af8e3..e77df79aa981 100644 --- a/app/PaymentDrivers/SquarePaymentDriver.php +++ b/app/PaymentDrivers/SquarePaymentDriver.php @@ -11,22 +11,27 @@ namespace App\PaymentDrivers; -use App\Http\Requests\Payments\PaymentWebhookRequest; -use App\Jobs\Util\SystemLogger; -use App\Models\ClientGatewayToken; -use App\Models\GatewayType; use App\Models\Invoice; use App\Models\Payment; +use App\Models\SystemLog; +use App\Models\GatewayType; use App\Models\PaymentHash; use App\Models\PaymentType; -use App\Models\SystemLog; +use App\Models\ClientContact; +use App\Factory\ClientFactory; +use App\Jobs\Util\SystemLogger; +use App\Utils\Traits\MakesHash; +use Square\Utils\WebhooksHelper; +use App\Models\ClientGatewayToken; +use App\Repositories\ClientRepository; +use Square\Models\WebhookSubscription; use App\PaymentDrivers\Square\CreditCard; use App\PaymentDrivers\Square\SquareWebhook; -use App\Utils\Traits\MakesHash; -use Square\Models\Builders\RefundPaymentRequestBuilder; +use App\Repositories\ClientContactRepository; use Square\Models\CreateWebhookSubscriptionRequest; -use Square\Models\WebhookSubscription; -use Square\Utils\WebhooksHelper; +use App\Http\Requests\Payments\PaymentWebhookRequest; +use App\PaymentDrivers\Factory\SquareCustomerFactory; +use Square\Models\Builders\RefundPaymentRequestBuilder; class SquarePaymentDriver extends BaseDriver { @@ -442,4 +447,191 @@ class SquarePaymentDriver extends BaseDriver return (bool) count($api_response->getErrors()) == 0; } + + public function importCustomers() + { + + $limit = 100; + + $api_response = $this->init() + ->square + ->getCustomersApi() + ->listCustomers(null, + $limit, + 'DEFAULT', + 'DESC' + ); + + if ($api_response->isSuccess()) { + + while ($api_response->getResult()->getCustomers()) { + + $customers = $api_response->getResult()->getCustomers(); + + $client_repo = new ClientRepository(new ClientContactRepository()); + + nlog($customers); + + foreach($customers as $customer) + { + + $data = (new SquareCustomerFactory())->convertToNinja($customer, $this->company_gateway->company); + $client = ClientContact::where('company_id', $this->company_gateway->company_id)->where('email', $customer->getEmailAddress())->first()->client ?? false; + + if(!$client) + $client = $client_repo->save($data, ClientFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id)); + + $this->client = $client; + + foreach($data['cards'] as $card) { + + if(ClientGatewayToken::where('company_id', $this->company_gateway->company_id)->where('token', $card['token'])->exists()) + continue; + + $this->storeGatewayToken($card); + + } + } + + $c = $api_response->getCursor(); + if ($c) { + + $api_response = $client->getCustomersApi()->listCustomers( + $c, + $limit, + 'DEFAULT', + 'DESC' + ); + } else { + break; + } + + + } + + } + } + + private function findClient($email = null) + { + + $email_address_string = $email ?? $this->client->present()->email(); + + $email_address = new \Square\Models\CustomerTextFilter(); + $email_address->setExact($email_address_string); + + $filter = new \Square\Models\CustomerFilter(); + $filter->setEmailAddress($email_address); + + $query = new \Square\Models\CustomerQuery(); + $query->setFilter($filter); + + $body = new \Square\Models\SearchCustomersRequest(); + $body->setQuery($query); + + $api_response = $this->init() + ->square + ->getCustomersApi() + ->searchCustomers($body); + + $customers = false; + + if ($api_response->isSuccess()) { + $customers = $api_response->getBody(); + $customers = json_decode($customers); + + if (count([$api_response->getBody(), 1]) == 0) { + $customers = false; + } + } else { + $errors = $api_response->getErrors(); + } + + if ($customers && property_exists($customers, 'customers')) { + return $customers->customers[0]->id; + } + + return false; + + } + + public function findOrCreateClient() + { + if($customer_id = $this->findClient()) + return $customer_id; + + return $this->createClient(); + } + + private function createClient() + { + $country = $this->client->country ? $this->client->country->iso_3166_2 : $this->client->company->country()->iso_3166_2; + + /* Step two - create the customer */ + $billing_address = new \Square\Models\Address(); + $billing_address->setAddressLine1($this->client->address1); + $billing_address->setAddressLine2($this->client->address2); + $billing_address->setLocality($this->client->city); + $billing_address->setAdministrativeDistrictLevel1($this->client->state); + $billing_address->setPostalCode($this->client->postal_code); + $billing_address->setCountry($country); + + $body = new \Square\Models\CreateCustomerRequest(); + $body->setGivenName($this->client->present()->name()); + $body->setFamilyName(''); + $body->setEmailAddress($this->client->present()->email()); + $body->setAddress($billing_address); + $body->setReferenceId($this->client->number); + $body->setNote('Created by Invoice Ninja.'); + + $api_response = $this->init() + ->square + ->getCustomersApi() + ->createCustomer($body); + + if ($api_response->isSuccess()) { + $result = $api_response->getResult(); + + return $result->getCustomer()->getId(); + } else { + $errors = $api_response->getErrors(); + nlog($errors); + + $error = end($errors); + + $data = [ + 'response' => $error->getDetail(), + 'error' => $error->getDetail(), + 'error_code' => $error->getCode(), + ]; + + return $this->processUnsuccessfulTransaction($data); + + } + } + + + + + + + + + + + + + + + + + + + + + + + + + }