├── .gitignore ├── credentials ├── production │ ├── onepay-keys.php │ └── webpay.cert └── integration │ ├── onepay-keys.php │ ├── webpay-plus-normal │ ├── 597020000540.cert │ └── 597020000540.key │ ├── webpay-plus-mall │ ├── 597044444401.cert │ └── 597044444401.key │ ├── webpay-oneclick-normal │ ├── 597044444405.cert │ └── 597044444405.key │ ├── webpay-plus-capture │ ├── 597044444404.cert │ └── 597044444404.key │ ├── webpay-patpass-normal │ ├── 597020000548.cert │ └── 597020000548.key │ └── webpay.cert ├── .github ├── FUNDING.yml └── workflows │ └── php.yml ├── src ├── Exceptions │ ├── Onepay │ │ ├── OnepayException.php │ │ ├── OnepayValidationException.php │ │ ├── CartEmptyException.php │ │ ├── CartNegativeAmountException.php │ │ ├── OnepayResponseException.php │ │ └── OnepayClientException.php │ ├── Webpay │ │ ├── WebpayException.php │ │ ├── InvalidSignatureException.php │ │ ├── TransactionTypeNullException.php │ │ ├── ServiceSdkUnavailableException.php │ │ ├── InvalidWebpayTransactionException.php │ │ └── ErrorResponseException.php │ ├── TransbankException.php │ ├── TransbankUnavailableException.php │ ├── Transbank │ │ └── InvalidServiceException.php │ └── Credentials │ │ ├── CredentialInvalidException.php │ │ └── CredentialsNotReadableException.php ├── Transactions │ ├── Item.php │ ├── Concerns │ │ ├── HasSecrets.php │ │ └── HasItems.php │ ├── WebpayMallTransaction.php │ ├── OnepayNullifyTransaction.php │ ├── WebpayTransaction.php │ └── AbstractTransaction.php ├── Responses │ ├── WebpayPlusResponse.php │ ├── WebpayPatpassResponse.php │ ├── OnepayResponse.php │ ├── WebpayOneclickResponse.php │ ├── AbstractResponse.php │ └── WebpayPlusMallResponse.php ├── Contracts │ ├── README.md │ ├── ResponseInterface.php │ ├── AdapterInterface.php │ ├── TransactionInterface.php │ └── ServiceInterface.php ├── ResponseFactories │ ├── AbstractResponseFactory.php │ └── WebpayResponseFactory.php ├── Clients │ ├── Webpay │ │ ├── Concerns │ │ │ ├── CommitsTransactions.php │ │ │ ├── RetrievesResults.php │ │ │ └── AcknowledgesTransactions.php │ │ ├── PlusCapture.php │ │ ├── SoapImplementation.php │ │ ├── PlusNullify.php │ │ ├── classmaps.php │ │ ├── PlusNormal.php │ │ └── WebpayClient.php │ └── AbstractClient.php ├── Adapters │ ├── AbstractAdapter.php │ └── OnepayAdapter.php ├── TransactionFactories │ ├── AbstractTransactionFactory.php │ └── OnepayTransactionFactory.php ├── Helpers │ └── Helpers.php ├── Concerns │ ├── HasCredentialOperations.php │ └── HasServiceGettersAndSetters.php └── Onepay.php ├── results ├── translation.php ├── webpay.oneclick.php └── onepay.php ├── examples ├── webpay-mall-normal │ ├── final.php │ ├── return.php │ └── start.php ├── webpay-oneclick │ ├── unregister.php │ ├── reverse.php │ ├── response.php │ ├── charge.php │ └── start.php ├── webpay-defer-capture-nullify │ ├── nullify.php │ ├── start.php │ ├── return.php │ └── capture.php ├── webpay-normal │ ├── final.php │ ├── return.php │ └── start.php ├── _master │ └── header.php ├── load.php ├── README.md ├── onepay │ ├── nullify.php │ ├── confirm.php │ └── start.php └── index.php ├── load.php ├── html └── webpayRedirect.php ├── tests ├── Unit │ ├── Clients │ │ ├── AbstractClientTest.php │ │ └── Webpay │ │ │ ├── WebpayClientTest.php │ │ │ ├── PlusCaptureTest.php │ │ │ └── PlusNullifyTest.php │ ├── Responses │ │ ├── OnepayResponseTest.php │ │ ├── WebpayPatpassResponseTest.php │ │ ├── WebpayPlusResponseTest.php │ │ ├── WebpayOneclickResponseTest.php │ │ ├── AbstractResponseTest.php │ │ └── WebpayPlusMallResponseTest.php │ ├── Adapters │ │ ├── AbstractAdapterTest.php │ │ └── OnepayAdapterTest.php │ ├── Helpers │ │ └── HelpersTest.php │ ├── Transactions │ │ ├── Concerns │ │ │ └── HasSecretsTest.php │ │ ├── WebpayMallTransactionTest.php │ │ ├── AbstractTransactionTest.php │ │ └── WebpayTransactionTest.php │ ├── Services │ │ └── OnepayTest.php │ └── TransactionFactories │ │ └── OnepayTransactionFactoryTest.php └── Feature │ └── Integration │ └── OnepayIntegrationTransactionsTest.php ├── phpunit.xml ├── LICENSE ├── LICENCIA ├── composer.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | composer.phar 3 | composer.lock 4 | vendor/ 5 | logs/ 6 | examples/webpay-oneclick/username.txt 7 | -------------------------------------------------------------------------------- /credentials/production/onepay-keys.php: -------------------------------------------------------------------------------- 1 | '2B571C49-C1B6-4AD1-9806-592AC68023B7', 5 | ]; -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # Help me support this package 2 | 3 | ko_fi: DarkGhostHunter 4 | custom: ['https://paypal.me/darkghosthunter'] 5 | -------------------------------------------------------------------------------- /src/Exceptions/Onepay/OnepayException.php: -------------------------------------------------------------------------------- 1 | include_once 'webpay.oneclick.php', 5 | 'webpay.plus' => include_once 'webpay.plus.php', 6 | 'onepay' => include_once 'onepay.php', 7 | ]; -------------------------------------------------------------------------------- /examples/webpay-mall-normal/final.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | echo '
';
8 | print_r($_POST);
9 | echo '
'; -------------------------------------------------------------------------------- /credentials/integration/onepay-keys.php: -------------------------------------------------------------------------------- 1 | '1a0c0639-bd2f-4846-8d26-81f43187e797', 5 | 'apiKey' => 'dKVhq1WGt_XapIYirTXNyUKoWTDFfxaEV63-O5jcsdw', 6 | 'secret' => '?XW#WOLG##FBAGEAYSNQ5APD#JF@$AYZ', 7 | ]; -------------------------------------------------------------------------------- /src/Exceptions/TransbankException.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->createUnregistration([ 8 | 'tbkUser' => $_POST['tbkUser'], 9 | 'username' => $_POST['username'] 10 | ]); 11 | 12 | echo '
';
13 | print_r($result);
14 | echo '
'; 15 | 16 | ?> -------------------------------------------------------------------------------- /load.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->createNullify([ 8 | 'authorizationCode' => $_POST['authorizationCode'], 9 | 'buyOrder' => $_POST['buyOrder'], 10 | 'authorizedAmount' => $_POST['authorizedAmount'], 11 | 'nullifyAmount' => $_POST['nullifyAmount'], 12 | ]); 13 | 14 | // Veamos el resultado. 15 | echo '
';
16 | print_r($result);
17 | echo '
'; 18 | -------------------------------------------------------------------------------- /src/Exceptions/Transbank/InvalidServiceException.php: -------------------------------------------------------------------------------- 1 | message = sprintf($this->message, $service); 14 | } 15 | } -------------------------------------------------------------------------------- /html/webpayRedirect.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Conectando con Webpay... 6 | 7 | 8 |
9 | 10 |
11 | 15 | 16 | -------------------------------------------------------------------------------- /src/Exceptions/Onepay/OnepayValidationException.php: -------------------------------------------------------------------------------- 1 | token: 16 | $this->isSuccess = true; 17 | break; 18 | case !!$this->detailOutput: 19 | $this->isSuccess = $this->detailOutput->responseCode === 0; 20 | break; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/Responses/WebpayPatpassResponse.php: -------------------------------------------------------------------------------- 1 | token: 16 | $this->isSuccess = true; 17 | break; 18 | case !!$this->detailOutput: 19 | $this->isSuccess = $this->detailOutput->responseCode === 0; 20 | break; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/Exceptions/Onepay/CartEmptyException.php: -------------------------------------------------------------------------------- 1 | message .= "\n" . "Transaction: " . $transaction; 17 | 18 | parent::__construct(); 19 | } 20 | 21 | 22 | } -------------------------------------------------------------------------------- /results/webpay.oneclick.php: -------------------------------------------------------------------------------- 1 | 'Transacción aprobada.', 5 | '-1' => 'Rechazo de transacción.', 6 | '-2' => 'Rechazo de transacción.', 7 | '-3' => 'Rechazo de transacción.', 8 | '-4' => 'Rechazo de transacción.', 9 | '-5' => 'Rechazo de transacción.', 10 | '-6' => 'Rechazo de transacción.', 11 | '-7' => 'Rechazo de transacción.', 12 | '-8' => 'Rechazo de transacción.', 13 | '-97' => 'Límite Oneclick: máximo monto diario de pago excedido.', 14 | '-98' => 'Límite Oneclick: máximo monto de pago excedido.', 15 | '-99' => 'Límite Oneclick: máxima cantidad de pagos diarios excedido.', 16 | ]; -------------------------------------------------------------------------------- /src/Contracts/README.md: -------------------------------------------------------------------------------- 1 | # Contratos 2 | 3 | Estas interfaces funcionan como contratos. Si quieres crear un nuevo servicio, implementa estas interfaces para que no pierdas la pista de qué hace qué cosa y cómo. 4 | 5 | Si quieres, puedes usar las clases abstractas si vas a reusar código, que podrás encontrar en cada directorio para: 6 | 7 | * Services 8 | * Transactions 9 | * TransactionFactories 10 | * Responses 11 | * ResponseFactories 12 | * Adapters 13 | * Clients 14 | 15 | No hay contratos para los `ResponseFactories` y `TransactionFactories`, pues no es necesario que cada servicio necesite una clase para crear respuestas o transacciones, pero es lo recomendado cuando hay distintos tipos de respuestas o transacciones. -------------------------------------------------------------------------------- /src/Exceptions/Onepay/CartNegativeAmountException.php: -------------------------------------------------------------------------------- 1 | message .= "\n" . "Transaction: " . $transaction; 17 | 18 | parent::__construct(); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/Exceptions/Webpay/InvalidWebpayTransactionException.php: -------------------------------------------------------------------------------- 1 | '', '-->' => '']; 15 | 16 | $this->message .= str_replace(array_keys($array), array_values($array), $message); 17 | 18 | parent::__construct($message, 0, $previous); 19 | } 20 | } -------------------------------------------------------------------------------- /src/ResponseFactories/AbstractResponseFactory.php: -------------------------------------------------------------------------------- 1 | service = $service; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/Clients/Webpay/Concerns/CommitsTransactions.php: -------------------------------------------------------------------------------- 1 | connector->initTransaction([ 24 | 'wsInitTransactionInput' => $transaction 25 | ]))->return; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Clients/Webpay/Concerns/RetrievesResults.php: -------------------------------------------------------------------------------- 1 | connector->getTransactionResult( 25 | new Fluid([ 26 | 'tokenInput' => $transaction 27 | ]) 28 | ))->return; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/Unit/Clients/AbstractClientTest.php: -------------------------------------------------------------------------------- 1 | client = new class(true, new Fluid(['foo' => 'bar'])) extends AbstractClient { 18 | protected function boot() {} 19 | }; 20 | } 21 | 22 | public function testSetAndGetEndpoint() 23 | { 24 | $this->assertNull($this->client->getEndpoint()); 25 | $this->client->setEndpoint('foo'); 26 | $this->assertEquals('foo', $this->client->getEndpoint()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src 6 | 7 | 8 | src/Clients/Webpay/SoapImplementation.php 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | tests/Unit 17 | 18 | 19 | tests/Feature 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/webpay-oneclick/reverse.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->createReverseCharge([ 8 | 'buyOrder' => $_POST['buyOrder'] 9 | ]); 10 | 11 | echo '
';
12 | print_r($result);
13 | echo '
'; 14 | ?> 15 | 16 | 17 | 18 | 19 | 20 | Conectando con Webpay... 21 | 22 | 23 |
24 | 26 | 28 | 29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Exceptions/Onepay/OnepayResponseException.php: -------------------------------------------------------------------------------- 1 | response = new OnepayResponse(['foo' => 'bar']); 17 | } 18 | 19 | public function testToArray() 20 | { 21 | $this->assertIsArray($this->response->toArray()); 22 | $this->assertArrayHasKey('foo', $this->response->toArray()); 23 | } 24 | 25 | public function testDynamicallySetSuccessStatus() 26 | { 27 | $this->response->dynamicallySetSuccessStatus(); 28 | 29 | $this->assertTrue($this->response->isSuccess()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/webpay-mall-normal/return.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->retrieveMallNormal($_POST['token_ws']); 8 | 9 | $confirm = $webpay->confirmMallNormal($_POST['token_ws']); 10 | 11 | echo '
';
12 | print_r($result);
13 | print_r($confirm);
14 | echo '
'; 15 | 16 | ?> 17 | 18 | 19 | 20 | 21 | 22 | Conectando con Webpay... 23 | 24 | 25 |
26 | 28 | 29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/webpay-normal/final.php: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | Resultado Webpay 11 | 12 | 13 | 14 |
15 |
16 |

Recepción desde Webpay

17 |
18 |
19 | La transacción terminó. No podemos volver a usar el token. 20 |
21 |
22 | 23 |
24 | 25 | Volver al índice 26 | 27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/webpay-oneclick/response.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->getRegistration($_POST['TBK_TOKEN']); 8 | 9 | $username = file_get_contents('username.txt'); 10 | 11 | echo '
';
12 | print_r($username);
13 | print_r($result->toArray());
14 | echo '
'; 15 | 16 | 17 | ?> 18 | 19 | 20 | 21 | 22 | 23 | Conectando con Webpay... 24 | 25 | 26 |
27 | 29 | 31 | 32 |

(Nos vamos a saltar el "finalURL")

33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Transactions/Concerns/HasSecrets.php: -------------------------------------------------------------------------------- 1 | hideSecrets = false; 22 | return $this; 23 | } 24 | 25 | /** 26 | * Hides Secrets on serialization 27 | * 28 | * @return $this 29 | */ 30 | public function hideSecrets() 31 | { 32 | $this->hideSecrets = true; 33 | return $this; 34 | } 35 | 36 | /** 37 | * If the current instance is hiddng it's secrets 38 | * 39 | * @return bool 40 | */ 41 | public function isHidingSecrets() 42 | { 43 | return $this->hideSecrets; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/Responses/OnepayResponse.php: -------------------------------------------------------------------------------- 1 | isSuccess = true; 33 | } 34 | 35 | /** 36 | * Transform the object to an array. 37 | * 38 | * @return array 39 | */ 40 | public function toArray() 41 | { 42 | return Helpers::arrayExcept($this->attributes, $this->hidden); 43 | } 44 | } -------------------------------------------------------------------------------- /examples/webpay-oneclick/charge.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->createCharge([ 8 | 'amount' => 9990, 9 | 'buyOrder' => $buyOrder = date('YmdHis') . '000', 10 | 'tbkUser' => $_POST['tbkUser'], 11 | 'username' => $_POST['username'], 12 | ]); 13 | 14 | echo '
';
15 | print_r($result);
16 | echo '
'; 17 | ?> 18 | 19 | 20 | 21 | 22 | 23 | Conectando con Webpay... 24 | 25 | 26 |
27 | 29 | 31 | 33 | 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Exceptions/Onepay/OnepayClientException.php: -------------------------------------------------------------------------------- 1 | getBody()->getContents()); 25 | } 26 | 27 | parent::__construct($error, $code, $previous); 28 | } 29 | } -------------------------------------------------------------------------------- /examples/webpay-defer-capture-nullify/start.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->createDefer([ 8 | 'returnUrl' => 'http://localhost:8080/webpay-defer-capture-nullify/return.php', 9 | 'finalUrl' => 'http://localhost:8080/webpay-defer-capture-nullify/final.php', 10 | 'buyOrder' => date('Y-m-d_H-i-s'), 11 | 'amount' => 9990, 12 | ]); 13 | 14 | // Veamos el resultado. 15 | echo '
';
16 | print_r($result);
17 | echo '
'; 18 | 19 | // HTML para redirigir la prueba 20 | ?> 21 | 22 | 23 | 24 | 25 | Conectando con Webpay... 26 | 27 | 28 |
29 | 30 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /examples/_master/header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/load.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->retrieveNormal($_POST['token_ws']); 8 | 9 | $confirm = $webpay->confirmNormal($_POST['token_ws']); 10 | 11 | echo '
';
12 | print_r($result);
13 | echo '
'; 14 | ?> 15 | 16 | 17 | 18 | 19 | 20 | Conectando con Webpay... 21 | 22 | 23 |
24 | 26 | 28 | 30 | 31 |

(Nos vamos a saltar el "finalURL")

32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/onepay/nullify.php: -------------------------------------------------------------------------------- 1 | onepay(); 6 | 7 | $nullify = $onepay->makeNullify([ 8 | 'occ' => $_POST['occ'], 9 | 'externalUniqueNumber' => $_POST['externalUniqueNumber'], 10 | 'authorizationCode' => $_POST['authorizationCode'], 11 | 'nullifyAmount' => $_POST['amount'], 12 | ]); 13 | 14 | $result = $nullify->commit(); 15 | ?> 16 | 17 | 18 | 19 | 20 | Conectando con Onepay... 21 | 22 | 23 | 24 |
25 |

Transacción eliminada:

26 |
toArray()) ?>
27 |
28 |
29 | 30 | Volver al índice 31 | 32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /examples/webpay-oneclick/start.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->createRegistration([ 8 | 'username' => $username = 'username_' . date('Y-m-d_H-i-s'), 9 | 'email' => 'email@commerceemaill.com', 10 | 'responseUrl' => 'http://localhost:8080/webpay-oneclick/response.php' 11 | ]); 12 | 13 | // Guardemos el nombre del usuario 14 | file_put_contents('username.txt', $username); 15 | 16 | // Veamos el resultado. 17 | echo '
';
18 | print_r($result);
19 | echo '
'; 20 | 21 | // HTML para redirigir la prueba 22 | ?> 23 | 24 | 25 | 26 | 27 | Conectando con Webpay... 28 | 29 | 30 |
31 | 32 | 33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Contracts/ResponseInterface.php: -------------------------------------------------------------------------------- 1 | 'foo', 'publicCert' => 'bar'])) extends WebpayClient { 15 | protected $endpointType = 'webpay'; 16 | }; 17 | 18 | $this->assertNull($client->getEndpoint()); 19 | $this->assertNull($client->getConnector()); 20 | 21 | $client->boot(); 22 | 23 | $this->assertNotNull($client->getEndpoint()); 24 | $this->assertNotNull($client->getConnector()); 25 | } 26 | 27 | public function testEndpointType() 28 | { 29 | $client = new class(true, new Fluid(['foo' => 'bar'])) extends WebpayClient { 30 | }; 31 | 32 | $this->assertNull($client->getEndpointType()); 33 | $client->setEndpointType('foo'); 34 | $this->assertEquals('foo', $client->getEndpointType()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/webpay-defer-capture-nullify/capture.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->createCapture([ 8 | 'authorizationCode' => $_POST['authorizationCode'], 9 | 'buyOrder' => $_POST['buyOrder'], 10 | 'captureAmount' => $_POST['captureAmount'], 11 | ]); 12 | 13 | // Veamos el resultado. 14 | echo '
';
15 | print_r($result);
16 | echo '
'; 17 | ?> 18 | 19 | 20 | 21 | 22 | Conectando con Webpay... 23 | 24 | 25 |
26 | 28 | 30 | 32 | 34 | 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /tests/Unit/Responses/WebpayPatpassResponseTest.php: -------------------------------------------------------------------------------- 1 | 'test-token']); 14 | $response->dynamicallySetSuccessStatus(); 15 | 16 | $this->assertTrue($response->isSuccess()); 17 | 18 | $response = new WebpayPatpassResponse([]); 19 | $response->dynamicallySetSuccessStatus(); 20 | 21 | $this->assertFalse($response->isSuccess()); 22 | 23 | $response = new WebpayPatpassResponse([ 24 | 'detailOutput' => (object)['responseCode' => 0] 25 | ]); 26 | $response->dynamicallySetSuccessStatus(); 27 | 28 | $this->assertTrue($response->isSuccess()); 29 | 30 | $response = new WebpayPatpassResponse([ 31 | 'detailOutput' => (object)['responseCode' => 1] 32 | ]); 33 | $response->dynamicallySetSuccessStatus(); 34 | 35 | $this->assertFalse($response->isSuccess()); 36 | 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Clients/Webpay/Concerns/AcknowledgesTransactions.php: -------------------------------------------------------------------------------- 1 | connector->acknowledgeTransaction($transaction); 25 | } 26 | 27 | /** 28 | * Acknowledges and accepts the Transaction 29 | * 30 | * @param $token 31 | * @return bool 32 | */ 33 | public function confirm($token) 34 | { 35 | $acknowledgeTransaction = new Fluid([ 36 | 'tokenInput' => $token 37 | ]); 38 | 39 | $this->performConfirm($acknowledgeTransaction); 40 | 41 | // Since we don't need any result, return the validation as a boolean 42 | return $this->validate(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LICENCIA: -------------------------------------------------------------------------------- 1 | Licencia MIT 2 | 3 | Derechos reservados (c) [2018] [Italo Israel Baeza Cabrera] 4 | 5 | Se concede permiso por la presente, libre de cargos, a cualquier persona 6 | que obtenga una copia de este software y de los archivos de documentación 7 | asociados (el "Software"), a utilizar el Software sin restricción, 8 | incluyendo sin limitación los derechos a usar, copiar, modificar, 9 | fusionar, publicar, distribuir, sublicenciar, y/o vender copias del 10 | Software, y a permitir a las personas a las que se les proporcione el 11 | Software a hacer lo mismo, sujeto a las siguientes condiciones: 12 | 13 | El aviso de copyright anterior y este aviso de permiso se incluirán en 14 | todas las copias o partes sustanciales del Software. 15 | 16 | EL SOFTWARE SE PROPORCIONA "COMO ESTÁ", SIN GARANTÍA DE NINGÚN TIPO, 17 | EXPRESA O IMPLÍCITA, INCLUYENDO PERO NO LIMITADO A GARANTÍAS DE 18 | COMERCIALIZACIÓN, IDONEIDAD PARA UN PROPÓSITO PARTICULAR E INCUMPLIMIENTO. 19 | EN NINGÚN CASO LOS AUTORES O PROPIETARIOS DE LOS DERECHOS DE AUTOR SERÁN 20 | RESPONSABLES DE NINGUNA RECLAMACIÓN, DAÑOS U OTRAS RESPONSABILIDADES, YA 21 | SEA EN UNA ACCIÓN DE CONTRATO, AGRAVIO O CUALQUIER OTRO MOTIVO, DERIVADAS 22 | DE, FUERA DE O EN CONEXIÓN CON EL SOFTWARE O SU USO U OTRO TIPO DE ACCIONES 23 | EN EL SOFTWARE. -------------------------------------------------------------------------------- /examples/webpay-mall-normal/start.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->createMallNormal([ 8 | 'returnUrl' => 'http://localhost:8080/webpay-mall-normal/return.php', 9 | 'finalUrl' => 'http://localhost:8080/webpay-mall-normal/final.php', 10 | 'sessionId' => 'alpha-session-1', 11 | 'buyOrder' => 10000001, 12 | 'items' => [ 13 | [ 14 | 'commerceCode' => 597044444402, 15 | 'amount' => 4990, 16 | 'buyOrder' => 20000001, 17 | ], 18 | [ 19 | 'commerceCode' => 597044444403, 20 | 'amount' => 9990, 21 | 'buyOrder' => 30000001, 22 | ], 23 | ] 24 | ]); 25 | 26 | echo '
';
27 | print_r($result);
28 | echo '
'; 29 | 30 | ?> 31 | 32 | 33 | 34 | 35 | Conectando con Webpay... 36 | 37 | 38 |
39 | 40 | 41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/webpay-normal/return.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $result = $webpay->retrieveNormal($_POST['token_ws']); 8 | 9 | $confirm = $webpay->confirmNormal($_POST['token_ws']); 10 | ?> 11 | 12 | 13 | 14 | 15 | 16 | Resultado Webpay 17 | 18 | 19 | 20 |
21 |
22 |

Resultado de la transacción

23 |
toArray()); ?>
24 |
25 | La transacción fue confirmada por separado. 26 |
27 |
28 | 29 |
30 | 32 |
33 | 34 |
35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /credentials/production/webpay.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDizCCAnOgAwIBAgIJAIXzFTyfjyBkMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV 3 | BAYTAkNMMQswCQYDVQQIDAJSTTERMA8GA1UEBwwIU2FudGlhZ28xEjAQBgNVBAoM 4 | CXRyYW5zYmFuazEMMAoGA1UECwwDUFJEMQswCQYDVQQDDAIxMDAeFw0xODAzMjkx 5 | NjA4MjhaFw0yMzAzMjgxNjA4MjhaMFwxCzAJBgNVBAYTAkNMMQswCQYDVQQIDAJS 6 | TTERMA8GA1UEBwwIU2FudGlhZ28xEjAQBgNVBAoMCXRyYW5zYmFuazEMMAoGA1UE 7 | CwwDUFJEMQswCQYDVQQDDAIxMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 8 | ggEBAKRqDk/pv8GeWnEaTVhfw55fThmqbFZOHEc/Un7oVWP+ExjD0kZ/aAwMJZ3d 9 | 9hpbBExftjoyJ0AYKJXA2CyLGxRp30LapBa2lMehzdP6tC5nrCYbDFz8r8ZyN/ie 10 | 4lBQ8GjfONq34cLQfM+tOxyazgDYRnZVD9tvOcqI5bFwFKqpn/yMr9Eya7gTo/OP 11 | wyz69sAF8MKr0YN941n6C1Cdrzp6cRftdj83nlI75Ue//rMYih/uQYiht4XWFjAA 12 | usoOG/IVVCCHhVQGE/Rp22dAF8JzWYZWCe+ICOKjEzEZPjDBqPoh9O+0eGTFVwn2 13 | qZf2iSLDKBOiha1wwzpTiiJV368CAwEAAaNQME4wHQYDVR0OBBYEFDfN1Tlj7wbn 14 | JIemBNO1XrUOikQpMB8GA1UdIwQYMBaAFDfN1Tlj7wbnJIemBNO1XrUOikQpMAwG 15 | A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBACzXPSHet7aZrQvMUN03jOqq 16 | w37brCWZ+L/+pbdOugVRAQRb2W+Z6gyrJ2BuUuiZLCXpjvXACSpwcSB3JesWs9KE 17 | YO8E8ofF7a6ORvi2Mw0vpBbwJLqnci1gVlAj3X8r/VbX2rGbvRy+BJAF769xr43X 18 | dtns0JIWwKud0xC3iRPMnewo/75HIblbN3guePfouoR2VgfBmeU72UR8O+OpjwbF 19 | vpidobGqTGvZtxRV5axer69WY0rAXRhTSfkvyGTXERCJ3vdsF/v9iNKHhERUnpV6 20 | KDrfvgD9uqWH12/89hfsfVN6iRH9UOE+SKoR/jHtvLMhVHpa80HVK1qdlfqUTZo= 21 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "darkghosthunter/transbank-api", 3 | "description": "Transbank SDK no oficial para PHP 7.4+", 4 | "keywords": [ 5 | "payments", 6 | "transbank", 7 | "api", 8 | "sdk" 9 | ], 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Italo Baeza C", 14 | "email": "yo@italobc.com", 15 | "homepage": "http://italobc.com", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": "^7.4||^8.0", 21 | "ext-curl": "*", 22 | "ext-json": "*", 23 | "ext-mbstring": "*", 24 | "ext-dom": "*", 25 | "ext-soap": "*", 26 | "luisurrutia/transbank-soap": "0.0.1", 27 | "robrichards/xmlseclibs": "3.0.4", 28 | "guzzlehttp/guzzle": "^7.0", 29 | "psr/log": "^1.0.1", 30 | "darkghosthunter/fluid": "^1.2.0" 31 | }, 32 | "require-dev": { 33 | "phpunit/phpunit": "^9.3", 34 | "mockery/mockery": "^1.4.1" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "DarkGhostHunter\\TransbankApi\\": "src" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | "Tests\\" : "tests" 44 | } 45 | }, 46 | "scripts": { 47 | "test": "vendor/bin/phpunit --coverage-clover build/logs/clover.xml", 48 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage" 49 | }, 50 | "config": { 51 | "sort-packages": true 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /credentials/integration/webpay-plus-normal/597020000540.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDeDCCAmACCQDjtGVIe/aeCTANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJj 3 | bDENMAsGA1UECAwEc3RnbzENMAsGA1UEBwwEc3RnbzEMMAoGA1UECgwDdGJrMQ0w 4 | CwYDVQQLDARjY3JyMRUwEwYDVQQDDAw1OTcwMjAwMDA1NDAxHTAbBgkqhkiG9w0B 5 | CQEWDmNjcnJAZ21haWwuY29tMB4XDTE4MDYwODEzNDYwNloXDTIyMDYwNzEzNDYw 6 | NlowfjELMAkGA1UEBhMCY2wxDTALBgNVBAgMBHN0Z28xDTALBgNVBAcMBHN0Z28x 7 | DDAKBgNVBAoMA3RiazENMAsGA1UECwwEY2NycjEVMBMGA1UEAwwMNTk3MDIwMDAw 8 | NTQwMR0wGwYJKoZIhvcNAQkBFg5jY3JyQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcN 9 | AQEBBQADggEPADCCAQoCggEBAL7jYAcTADgZTSOxcObBxmNaegwehDCvN0i+G9WS 10 | C0ibP/PzAl/D5MrNwryZkiIilO351pIF3IRHalyVfrc4KBA/8vfbV4KDLLItJmvr 11 | vWLT76U+wWua5OR6S7mhTXrhN5fpqZFw2WShUmSdX1fx8p9wNWc/u/l9qohqwFln 12 | Y3hrCJM+K7rjBS0FXT1a3QMRFqA0cmxFIa2kCdZMJsfdhxX0ZbGzQJhJYxvZ4Mf/ 13 | vySwNvHLPaFC8uPzO31VM4qCrASZo0SXerOKyNmCA6bpenZoJaFoBH83yzZwLGYS 14 | a8iTQa9lmxOgy+cf1Nl0HIY4rITGwyD45g4EtByyzI0QjKUCAwEAATANBgkqhkiG 15 | 9w0BAQsFAAOCAQEAhX2/fZ6+lyoY3jSU9QFmbL6ONoDS6wBU7izpjdihnWt7oIME 16 | a51CNssla7ZnMSoBiWUPIegischx6rh8M1q5SjyWYTvnd3v+/rbGa6d40yZW3m+W 17 | p/3Sb1e9FABJhZkAQU2KGMot/b/ncePKHvfSBzQCwbuXWPzrF+B/4ZxGMAkgxtmK 18 | WnWrkcr2qakpHzERn8irKBPhvlifW5sdMH4tz/4SLVwkek24Sp8CVmIIgQR3nyR9 19 | 8hi1+Iz4O1FcIQtx17OvhWDXhfEsG0HWygc5KyTqCkVBClVsJPRvoCSTORvukcuW 20 | 18gbYO3VlxwXnvzLk4aptC7/8Jq83XY8o0fn+A== 21 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /credentials/integration/webpay-plus-mall/597044444401.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDrDCCApQCCQCDHU0/ZL/yojANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMC 3 | Y2wxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCHNhbnRpYWdvMSEwHwYD 4 | VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTATBgNVBAMMDDU5NzA0NDQ0 5 | NDQwMTEmMCQGCSqGSIb3DQEJARYXYW1hbGRvbmFkb0B0cmFuc2JhbmsuY2wwHhcN 6 | MTgwOTA0MTQwMzE4WhcNMjIwMzI3MTQwMzE4WjCBlzELMAkGA1UEBhMCY2wxEzAR 7 | BgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCHNhbnRpYWdvMSEwHwYDVQQKDBhJ 8 | bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTATBgNVBAMMDDU5NzA0NDQ0NDQwMTEm 9 | MCQGCSqGSIb3DQEJARYXYW1hbGRvbmFkb0B0cmFuc2JhbmsuY2wwggEiMA0GCSqG 10 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrnHw/0QirzFPpS1EAvqmY2lyBi4hcdS+0 11 | +5j4Cjbwu1uwlBWA9cnYKsxi2rcYfWQ8BqN0XS118w5JCDFOedawwV1jqN6Xa+EX 12 | W98q+bv3IsyuohFfuX99luV1Yl2hK6rVvfFM9gEooYWF79K9ik7zx2864fhYiIB9 13 | FPWAVeQRb3HIDvS8r/hFlH3d/bbQQuHywcEzA/f1ec2ntznYD5/V+QlU/kXwblRM 14 | AL+D+MNkwKu2cLDG7fuPJdMSlABNdQ3VeuyMmKum80F8i9dCWTgB5cSPlrs9gTic 15 | BJl83BJzWSkObsbo+F4ORRc3UkQWxwL/H0GlW9kgCNpcwv9AIVXvAgMBAAEwDQYJ 16 | KoZIhvcNAQELBQADggEBACv0krFTiPCwsw0pwKfHJUqhP+k2B7FkdSFhpdd8OiRX 17 | 50E9aY9oiasuojyYA0mdrWDZvyKsxvMGuSzxrxgg42Wsb2DPR5Uc99V2+9rpODFV 18 | nPWeuhAgBUfNK3rZ+qIz1FyrzYUTPcK0BzStbpdclb+LEh7I0wTegSj7skctm8M2 19 | BQmFaS67DUmr0ReI4ZHvWMkDjqjlK8mzx0f7nOdarq3Cxhg3QMqOilfGtvrZrtos 20 | q8/WPGded+bP8kBZ2Rs6oUEBBQfVnAPI50YRXZJjyAzqSwx8MhFztAgE/LaYbvZs 21 | xNB2I18V5oNmOCXHhfqneSstxMBWt3W8rd/0+JSfWLc= 22 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /credentials/integration/webpay-oneclick-normal/597044444405.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDrDCCApQCCQCLlKISnBv1OTANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMC 3 | Y2wxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCHNhbnRpYWdvMSEwHwYD 4 | VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTATBgNVBAMMDDU5NzA0NDQ0 5 | NDQwNTEmMCQGCSqGSIb3DQEJARYXYW1hbGRvbmFkb0B0cmFuc2JhbmsuY2wwHhcN 6 | MTgwOTA0MTQxNDE0WhcNMjIwMzI3MTQxNDE0WjCBlzELMAkGA1UEBhMCY2wxEzAR 7 | BgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCHNhbnRpYWdvMSEwHwYDVQQKDBhJ 8 | bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTATBgNVBAMMDDU5NzA0NDQ0NDQwNTEm 9 | MCQGCSqGSIb3DQEJARYXYW1hbGRvbmFkb0B0cmFuc2JhbmsuY2wwggEiMA0GCSqG 10 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjxLzvsZS2OViuohAOVkAyqDmR82utmUJl 11 | yQLUsbMJ9w+7subNrZzYXVDvMoQupVOjXC5lRLWKeFia2Dg97EMpqT+6vIBFHe7L 12 | aSqrfIbchA0h1BhGkBSXxK83Im9RW0DQ3qfCNqqxO/URpw4ux9H70c29FdpZKK1c 13 | 0VruLYbSI3+mddtrv3qZQxUzAk+RXpKLrrTznrqa+qRKe/O6UBoL956/UojIfmgX 14 | bbKPJZEgz4r1k3HsKiyfGCa3p7/wBrMYHEDuBfFXoNC068vqTgCi21SujaExctRl 15 | FLfHgaO0kNSOkuNQgekrlPProPx0Y34q/9/9jtsBYwdRCqs8eQBxAgMBAAEwDQYJ 16 | KoZIhvcNAQELBQADggEBAGQWdgUHhWXnGIiqE/0b1N2YPr2l1CTu86edj/3ySp1A 17 | 7yIeWOiI1NUhMVXTt/uGw4C1WC4Ir3nhB1E0yrc65VF0GboE8m9ilj98NbkQKz0/ 18 | dr3/TFb9Fc37WIMFoKsG2tnEXhLZxaahglEDdBcoL+I78K+JFtL92N7+Sns5zAmy 19 | DDKf/7bKvTBF5vXQzgYWkrGFweppVU1xfgCn5KFdqQSJZzvcu1xuCRSngLbcpBEW 20 | JlzTNzZ7K+siy5V9cKQtUW3h/KyMeP9KCE0YUnXvtiGr2yeqUviUAqDiSzcCmQDR 21 | XE4/CA2Yzlv/+n9JVsvFBTAyIvYfG3mqr8KdkL238sc= 22 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /credentials/integration/webpay-plus-capture/597044444404.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDrDCCApQCCQDxS6RHDwxUnjANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UEBhMC 3 | Q0wxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCHNhbnRpYWdvMSEwHwYD 4 | VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTATBgNVBAMMDDU5NzA0NDQ0 5 | NDQwNDEmMCQGCSqGSIb3DQEJARYXYW1hbGRvbmFkb0B0cmFuc2JhbmsuY2wwHhcN 6 | MTgwOTA0MTQxMDQ3WhcNMjIwMzI3MTQxMDQ3WjCBlzELMAkGA1UEBhMCQ0wxEzAR 7 | BgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCHNhbnRpYWdvMSEwHwYDVQQKDBhJ 8 | bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFTATBgNVBAMMDDU5NzA0NDQ0NDQwNDEm 9 | MCQGCSqGSIb3DQEJARYXYW1hbGRvbmFkb0B0cmFuc2JhbmsuY2wwggEiMA0GCSqG 10 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrrYXXUNVXZyIv9L/Mqvw2Z6xk1Sgje3/0 11 | Rtnmb3suMf9HWzbQzElaObLR/4jrg+8mQY69Bq4F0mgaKIJ6JXepj4+mmA5CYyjz 12 | Fdo/MSutWvQX1vHeBupK6qL+7Ak0lFZSze1iaVD9ZCsodIzGlGRW2FaginJHdQQG 13 | mv030yEB0NqskK/91/0fK7dGkTtQsUKcIeL/LcNU9iLdOddrjGj18TeJW7Ew2MJQ 14 | 73caoRNhUJGghb/bft+t3y2BnduI2ZhGpvE7qMi//W4QmzabE9pb4WZ2lbj7IzW0 15 | rx7yZZX86uqmyVk7SapRVjXqmEklbtp3h+LRXf5MJHCBjQwLrHq7AgMBAAEwDQYJ 16 | KoZIhvcNAQELBQADggEBACo42LiT6Da6Dq6kLrz3ja8dBge2SfCu/gnA+57lENAx 17 | D1Nq3lMqOE2dAoQXM+qwkBvduPaqFUzb4HV1b11PoAgeWR3ksoaKiWwjY5+p/snl 18 | Z/EITwHYhfl9cmuVQFC09AQC/3brrP62fYzKP03CkGrxfVFP0Q0eLzP3w8x4XMzG 19 | 9VmMMHFICFYEEyUiQT22X8SpFtUakNCfJzK65zXGAxJqZKTVYhjcYB+HBIAqitGS 20 | hF+F68G9XN7twijNIuseJt/I98R7UazON7EeP7kAz/UylVNOVmYq+pQbU4fG9QjQ 21 | CZ8F118V03v3IQYXwTmOHge9moBwyTkcnI5nql346jg= 22 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /credentials/integration/webpay-patpass-normal/597020000548.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDujCCAqICCQDHWKiW6dFYqjANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UEBhMC 3 | Q0wxETAPBgNVBAgMCFNhbnRpYWdvMRIwEAYDVQQKDAlUcmFuc2JhbmsxETAPBgNV 4 | BAcMCFNhbnRpYWdvMRUwEwYDVQQDDAw1OTcwMjAwMDA1NDgxFzAVBgNVBAsMDkNh 5 | bmFsZXNSZW1vdG9zMSUwIwYJKoZIhvcNAQkBFhZpbnRlZ3JhZG9yZXNAdmFyaW9z 6 | LmNsMB4XDTE2MDYyODIwMDQ0N1oXDTI0MDYyNjIwMDQ0N1owgZ4xCzAJBgNVBAYT 7 | AkNMMREwDwYDVQQIDAhTYW50aWFnbzESMBAGA1UECgwJVHJhbnNiYW5rMREwDwYD 8 | VQQHDAhTYW50aWFnbzEVMBMGA1UEAwwMNTk3MDIwMDAwNTQ4MRcwFQYDVQQLDA5D 9 | YW5hbGVzUmVtb3RvczElMCMGCSqGSIb3DQEJARYWaW50ZWdyYWRvcmVzQHZhcmlv 10 | cy5jbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLeHJx5wK/9OSmM 11 | JPts4mClAMZPxNC4aRvCksiafSpdRtPSPMQYUpxdt16RJuoK4Cpsc2xrY/LfLvT+ 12 | eLDcTa3LNLWsFdKh387Eut4QCddueC3mQLk1aVl1JxJeA1iPT6uuzllKL1Dy/5kM 13 | 3GQSUobKQus19Lp31kZ6A3jbcdO2o/8atD117ajhCYcmOhMkbDvV1j1SiJuWZ1Qg 14 | YPZra2WZMMEThE5Q+uZnghOoGAulhaweRVL40u9gpwNGcpxY/1W+GJoujreTN39D 15 | ZhhvatJMHjkHzcr/nv0KAeylRy66THXCju9A/iLTyuMHVJTn202SWFlGiuhf89i5 16 | BdADw9ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEARz2BbG8QGKqjUYorkCe+eaE5 17 | WnZN5q8/ihisJtsa9yXO7DUe8912094Wd/ZqwYQ1eBr0vEdwQ1Mit2lkBOkyNqR3 18 | af3/8znCxiTqvJdo4r3sp6nZV2m6zjicQwJ3aWFP8mqeTsyG3rMZBin0QaDoYCM+ 19 | 5qVZhQBycggsPMPnZ3fvBIslWCd6JBPYZ4agXNLdAsTmxYxjpuyOM+qTN9hdYdzb 20 | jaJ/IVa8NZrrSZU6BxooybSHNJ5+x0dc9Q/6A7txTnjTj8Iy9gfjokXRgpADpFq9 21 | mnf2hxewHnOGRcfAHBgS6vrpuAJ7/yIMewcMtu09ukFY7/d23CDPGVisDdDJwA== 22 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /examples/onepay/confirm.php: -------------------------------------------------------------------------------- 1 | onepay(); 6 | 7 | $result = $onepay->getTransaction([ 8 | 'occ' => $_POST['occ'], 9 | 'externalUniqueNumber' => $_POST['externalUniqueNumber'], 10 | ]); 11 | ?> 12 | 13 | 14 | 15 | 16 | Conectando con Onepay... 17 | 18 | 19 | 20 |
21 |

Respuesta:

22 |
23 |

Transacción recuperada:

24 |
toArray()) ?>
25 |
26 |
27 | 28 | 29 | 30 | 31 |
32 | 35 |
36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /src/Clients/AbstractClient.php: -------------------------------------------------------------------------------- 1 | isProduction = $isProduction; 39 | $this->credentials = $credentials; 40 | } 41 | 42 | /** 43 | * Get the Endpoint 44 | * 45 | * @return string 46 | */ 47 | public function getEndpoint() 48 | { 49 | return $this->endpoint; 50 | } 51 | 52 | /** 53 | * Set the Endpoint 54 | * 55 | * @param string $endpoint 56 | */ 57 | public function setEndpoint(string $endpoint) 58 | { 59 | $this->endpoint = $endpoint; 60 | } 61 | 62 | /** 63 | * Boot the connector 64 | * 65 | * @return void 66 | */ 67 | abstract protected function boot(); 68 | } -------------------------------------------------------------------------------- /tests/Unit/Responses/WebpayPlusResponseTest.php: -------------------------------------------------------------------------------- 1 | 'bar', 15 | 'token' => 'mock-token' 16 | ]); 17 | 18 | $response->dynamicallySetSuccessStatus(); 19 | 20 | $this->assertTrue($response->isSuccess()); 21 | 22 | $response = new WebpayPlusResponse([ 23 | 'foo' => 'bar', 24 | ]); 25 | 26 | $response->dynamicallySetSuccessStatus(); 27 | 28 | $this->assertFalse($response->isSuccess()); 29 | } 30 | 31 | public function testDynamicallySetSuccessStatusWithDetailedOutput() 32 | { 33 | $response = new WebpayPlusResponse([ 34 | 'foo' => 'bar', 35 | 'detailOutput' => (object)['responseCode' => 0], 36 | ]); 37 | 38 | $response->dynamicallySetSuccessStatus(); 39 | 40 | $this->assertTrue($response->isSuccess()); 41 | 42 | $response = new WebpayPlusResponse([ 43 | 'foo' => 'bar', 44 | 'detailOutput' => (object)['responseCode' => 1], 45 | ]); 46 | 47 | $response->dynamicallySetSuccessStatus(); 48 | 49 | $this->assertFalse($response->isSuccess()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /credentials/integration/webpay.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEDzCCAvegAwIBAgIJAMaH4DFTKdnJMA0GCSqGSIb3DQEBCwUAMIGdMQswCQYD 3 | VQQGEwJDTDERMA8GA1UECAwIU2FudGlhZ28xETAPBgNVBAcMCFNhbnRpYWdvMRcw 4 | FQYDVQQKDA5UUkFOU0JBTksgUy5BLjESMBAGA1UECwwJU2VndXJpZGFkMQswCQYD 5 | VQQDDAIyMDEuMCwGCSqGSIb3DQEJARYfc2VndXJpZGFkb3BlcmF0aXZhQHRyYW5z 6 | YmFuay5jbDAeFw0xODA4MjQxOTU2MDlaFw0yMTA4MjMxOTU2MDlaMIGdMQswCQYD 7 | VQQGEwJDTDERMA8GA1UECAwIU2FudGlhZ28xETAPBgNVBAcMCFNhbnRpYWdvMRcw 8 | FQYDVQQKDA5UUkFOU0JBTksgUy5BLjESMBAGA1UECwwJU2VndXJpZGFkMQswCQYD 9 | VQQDDAIyMDEuMCwGCSqGSIb3DQEJARYfc2VndXJpZGFkb3BlcmF0aXZhQHRyYW5z 10 | YmFuay5jbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJN+OJgQQqMb 11 | iRZDb3x+JoTfSjyYsRc5k2CWvLpTPFxXuhDyp6mbdIpWIiNYEC4vufVZo5A3THar 12 | cbnJRlW/4NVv5QM3gHN9WJ4QeIsrTLtvcIPlfUJNPLNeDqy84zum2YqAFmX5LWsp 13 | SF1Ls6n7el8KNJAceaU+2ooN8QZdFZ3RnMc2vrHY7EU6wYGmf/VCEaDZCKqY6ElY 14 | mt6/9b2lkhpQLdBn01IqqFpGrD+5DLmYrQur4/1BDVtdNLggX0K7kPk/mkPDq4ME 15 | ytkc9/RI5HfJWoQ4EDQF6qcqPqxlMFDf5KEaoLVL230EdwOl0UyvlF25S9ubRyHy 16 | mKWIEFSSXe0CAwEAAaNQME4wHQYDVR0OBBYEFP3nYSPX3YKF11RArC09hxjEMMBv 17 | MB8GA1UdIwQYMBaAFP3nYSPX3YKF11RArC09hxjEMMBvMAwGA1UdEwQFMAMBAf8w 18 | DQYJKoZIhvcNAQELBQADggEBAFHqOPGeg5IpeKz9LviiBGsJDReGVkQECXHp1QP4 19 | 8RpWDdXBKQqKUi7As97wmVksweaasnGlgL4YHShtJVPFbYG9COB+ElAaaiOoELsy 20 | kjF3tyb0EgZ0Z3QIKabwxsxdBXmVyHjd13w6XGheca9QFane4GaqVhPVJJIH/zD2 21 | mSc1boVSpaRc1f0oiMtiZf/rcY1/IyMXA9RVxtOtNs87Wjnwq6AiMjB15fLHfT7d 22 | R48O6P0ZpWLlZwScyqDWcsg/4wNCL5Kaa5VgM03SKM6XoWTzkT7p0t0FPZVoGCyG 23 | MX5lzVXafBH/sPd545fBH2J3xAY3jtP764G4M8JayOFzGB0= 24 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /examples/webpay-normal/start.php: -------------------------------------------------------------------------------- 1 | webpay(); 6 | 7 | $payment = $webpay->makeNormal([ 8 | 'returnUrl' => currentUrlPath('return.php'), 9 | 'finalUrl' => currentUrlPath('final.php'), 10 | 'buyOrder' => 'myOrder-' . rand(1,9999), 11 | 'amount' => rand(1000, 29999), 12 | ]); 13 | 14 | $result = $payment->commit(); 15 | 16 | ?> 17 | 18 | 19 | 20 | 21 | Conectando con Webpay... 22 | 23 | 24 | 25 |
26 |
27 |

Información de pago enviado

28 |
toArray()); ?>
29 |

Resultado devuelto

30 |
toArray()); ?>
31 |
32 |
33 | 34 |
35 | 38 |
39 | Esto hará una petición HTTP POST hacia Transbank. 40 |
41 |
42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP Composer 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | test: 9 | 10 | runs-on: ubuntu-latest 11 | strategy: 12 | fail-fast: true 13 | matrix: 14 | php: [7.4, 8.0] 15 | dependency-version: [prefer-stable, prefer-lowest] 16 | 17 | name: PHP ${{ matrix.php }} - ${{ matrix.dependency-version }} 18 | 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | 23 | - name: Setup PHP 24 | uses: shivammathur/setup-php@v2 25 | with: 26 | php-version: ${{ matrix.php }} 27 | extensions: mbstring, intl 28 | coverage: xdebug 29 | 30 | - name: Cache dependencies 31 | uses: actions/cache@v2 32 | with: 33 | path: ~/.composer/cache/files 34 | key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 35 | restore-keys: ${{ runner.os }}-php-${{ matrix.php }}-composer- 36 | 37 | - name: Install dependencies 38 | run: composer update --${{ matrix.dependency-version }} --prefer-dist --no-progress --no-suggest 39 | 40 | - name: Run Tests 41 | run: composer run-script test 42 | 43 | - name: Upload Coverage to Coveralls 44 | env: 45 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | COVERALLS_SERVICE_NAME: github 47 | run: | 48 | rm -rf composer.* vendor/ 49 | composer require php-coveralls/php-coveralls 50 | vendor/bin/php-coveralls --coverage_clover=build/logs/clover.xml 51 | -------------------------------------------------------------------------------- /src/Transactions/WebpayMallTransaction.php: -------------------------------------------------------------------------------- 1 | null, 18 | ]; 19 | 20 | /** 21 | * OnepayTransaction constructor. 22 | * 23 | * @param array $attributes 24 | */ 25 | public function __construct(array $attributes = []) 26 | { 27 | if (isset($attributes['items'])) { 28 | $this->setItemsFromConstruct($attributes['items']); 29 | unset($attributes['items']); 30 | } 31 | 32 | parent::__construct($attributes); 33 | } 34 | 35 | /** 36 | * Dynamically call the Items helpers as *Order* methods 37 | * 38 | * @param string $method 39 | * @param array $parameters 40 | * @return WebpayTransaction 41 | */ 42 | public function __call($method, $parameters) 43 | { 44 | if (strpos($method, 'Order') !== false) { 45 | return $this->{str_replace('Order', 'Item', $method)}(...$parameters); 46 | } 47 | 48 | return parent::__call($method, $parameters); 49 | } 50 | 51 | /** 52 | * Transform the object to an array. 53 | * 54 | * @return array 55 | */ 56 | public function toArray() 57 | { 58 | return array_merge( 59 | $this->attributes, 60 | ['items' => $this->items] 61 | ); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /src/Transactions/OnepayNullifyTransaction.php: -------------------------------------------------------------------------------- 1 | issuedAt = $this->issuedAt ?? time(); 32 | } 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Custom Array representation 37 | |-------------------------------------------------------------------------- 38 | */ 39 | 40 | /** 41 | * Transform the object to an array. 42 | * 43 | * @return array 44 | */ 45 | public function toArray() 46 | { 47 | if ($this->hideSecrets) { 48 | return Helpers::arrayExcept($this->attributes, ['appKey', 'apiKey', 'signature']); 49 | } 50 | 51 | return $this->attributes; 52 | } 53 | } -------------------------------------------------------------------------------- /src/Contracts/AdapterInterface.php: -------------------------------------------------------------------------------- 1 | count() === 1 && (Helpers::arrayFirst($this->attributes) === true)) { 30 | $this->isSuccess = true; 31 | $this->attributes = []; 32 | } 33 | 34 | if ($this->{$this->tokenName} || $this->reversed) { 35 | $this->isSuccess = true; 36 | } 37 | 38 | if (($this->attributes['responseCode'] ?? null) === 0) { 39 | $this->isSuccess = true; 40 | } 41 | } 42 | 43 | /* 44 | |-------------------------------------------------------------------------- 45 | | Getters and Setters 46 | |-------------------------------------------------------------------------- 47 | */ 48 | 49 | /** 50 | * Catch the `urlWebpay` from Oneclick responses and fill it as `url` 51 | * 52 | * @param string $urlWebpay 53 | */ 54 | public function setUrlWebpayAttribute(string $urlWebpay) 55 | { 56 | $this->attributes['url'] = $urlWebpay; 57 | } 58 | } -------------------------------------------------------------------------------- /tests/Unit/Responses/WebpayOneclickResponseTest.php: -------------------------------------------------------------------------------- 1 | $url = 'http://webpay4g.this.com/is-a-test/', 14 | 'TBK_TOKEN' => $token = 'test-token', 15 | ]); 16 | 17 | $this->assertEquals($url, $response->url); 18 | $this->assertEquals($token, $response->TBK_TOKEN); 19 | 20 | } 21 | 22 | public function testDynamicallySetSuccessStatus() 23 | { 24 | $foo = new WebpayOneclickResponse([true]); 25 | $foo->dynamicallySetSuccessStatus(); 26 | 27 | $this->assertTrue($foo->isSuccess()); 28 | 29 | $bar = new WebpayOneclickResponse([ 30 | 'urlWebpay' => $url = 'http://webpay4g.this.com/is-a-test/', 31 | 'TBK_TOKEN' => $token = 'test-token', 32 | ]); 33 | $bar->dynamicallySetSuccessStatus(); 34 | 35 | $this->assertTrue($bar->isSuccess()); 36 | 37 | $quz = new WebpayOneclickResponse(['responseCode' => 0]); 38 | $quz->dynamicallySetSuccessStatus(); 39 | 40 | $this->assertTrue($quz->isSuccess()); 41 | 42 | $qux = new WebpayOneclickResponse(['responseCode' => 1]); 43 | $qux->dynamicallySetSuccessStatus(); 44 | 45 | $this->assertFalse($qux->isSuccess()); 46 | 47 | $quuz = new WebpayOneclickResponse(['reversed' => 'anything']); 48 | $quuz->dynamicallySetSuccessStatus(); 49 | 50 | $this->assertTrue($quuz->isSuccess()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /credentials/integration/webpay-plus-mall/597044444401.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAq5x8P9EIq8xT6UtRAL6pmNpcgYuIXHUvtPuY+Ao28LtbsJQV 3 | gPXJ2CrMYtq3GH1kPAajdF0tdfMOSQgxTnnWsMFdY6jel2vhF1vfKvm79yLMrqIR 4 | X7l/fZbldWJdoSuq1b3xTPYBKKGFhe/SvYpO88dvOuH4WIiAfRT1gFXkEW9xyA70 5 | vK/4RZR93f220ELh8sHBMwP39XnNp7c52A+f1fkJVP5F8G5UTAC/g/jDZMCrtnCw 6 | xu37jyXTEpQATXUN1XrsjJirpvNBfIvXQlk4AeXEj5a7PYE4nASZfNwSc1kpDm7G 7 | 6PheDkUXN1JEFscC/x9BpVvZIAjaXML/QCFV7wIDAQABAoIBAF/oGoBHwELS9GpD 8 | D0gNRhcIof48Dr8tNrY8jebBPqcW7k0m1UW3F1DZylPMy9rB6Qyq4RqdIFT0ux0R 9 | mQy0hslNp3WU4KFbRvaY/4Wy/9tD9YP7Sx5mOtvjQuVxTcZO8zB08LAEI+2jJ04N 10 | E4eeDjWrVXxg4TwJPVWqKvHIDqe26CfMlKohSpcCpmq3HQknnFfuxGGlNGdrX4YR 11 | v4BeoSsAG8Ak+cCkGBJ2LcrZpw+GJjs0SkvOVO1+G+vixYPDcor1moB1AnQ/tkrz 12 | gSrRIl+Et3nq5XmmxQejOgMMWaXR2RXutdgXq4w3s4FSwABv5Zw1zAA/yapfk1uH 13 | zJ/OpuECgYEA22kVGXhoR0onMSKKHnbtO3s3tmrgLwVQAMaEwYy8KNnIWkCLszlT 14 | KtJ7nmEDdMysbHpb1EeNAoKg/DKY0YgneWrmmh3JozUp18dXEeHqEVPH1X9XT017 15 | M24nqe65deFu9SKhZv9SQdj69iJLnRxPHSae/p5wb2ORr/XG+9ZX6OkCgYEAyDrK 16 | 95yH2b5CcZXvT+9laIO8OZvppTP923a8stofPfBXRmqRZdhLLOVMJhBiQtRSGz4w 17 | Tk0T1LC9FN9Y5y4HLbyYDuYxqda+MqdBoYgsvep4ozVNyE7UDdRTKOjin8xIArAn 18 | mPvhjVBtpvQE+r9A4CfLe2smyHUtW48nAxgugRcCgYAjgfgGLTRDBT8edoZ/s6Nk 19 | 0uYLQXSSZ3uxBG+LmykAO25vHK7/DDHnZjTXRr/2cQEedRbTXdj2JQnEhrOwhSZO 20 | QfybyGJPZVUmNH5kyHjG4RYf+QG6NcHQau1EVPvylc8NINOaBYvcWC8VEivGe0Ra 21 | ZVupvR5ZCHYVUeMn8mI7sQKBgQDG5cgq8Z3tSVbdWBAyOl9k07+NBniwt5XLhQZr 22 | L8trDqzTcRbfsVzzyw66nPnO4vRwxXTcwyoY1DvvWPIKKynMYBQ4cKgSyxOCY60J 23 | VakEOr79ePy8Jrn0xt6Yu8Yq8JTzvqKHEGZ8ptFVz/6GSqeaQ02ZWtZauDOHSQt6 24 | wnGnnwKBgFbTBEwXl89uZZ/25z1mA5D9nqHTj/A0GYc9762xc/bvkvi59DeYbNSH 25 | J7jKHS50kE4sS/E4p7e9/G4jZTe/nvEsstfFZprRF31xlVY9Y/1OPysGYIJPOTAg 26 | EBEKSypPpswFcn/jSeIGii7aEb5h6OyNpnSMbBvFxhhUJ1PPpUQG 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /tests/Unit/Adapters/AbstractAdapterTest.php: -------------------------------------------------------------------------------- 1 | adapter = new class extends AbstractAdapter { 19 | public function getCredentials() { return $this->credentials; } 20 | public function commit(TransactionInterface $transaction, $options = null) {} 21 | public function retrieveAndConfirm($transaction, $options = null) {} 22 | 23 | public function __construct() 24 | { 25 | } 26 | }; 27 | } 28 | 29 | public function testSetAndGetClient() 30 | { 31 | $this->adapter->setClient(new Fluid(['foo' => 'bar'])); 32 | 33 | $this->assertEquals('bar', $this->adapter->getClient()->foo); 34 | } 35 | 36 | public function testSetCredentials() 37 | { 38 | $this->adapter->setCredentials(new Fluid(['foo' => 'bar'])); 39 | 40 | $this->assertEquals('bar', $this->adapter->getCredentials()->foo); 41 | } 42 | 43 | public function testIsProduction() 44 | { 45 | $this->assertFalse($this->adapter->isProduction()); 46 | } 47 | 48 | public function testSetIsProduction() 49 | { 50 | $this->adapter->setIsProduction(false); 51 | $this->assertFalse($this->adapter->isProduction()); 52 | $this->adapter->setIsProduction(true); 53 | $this->assertTrue($this->adapter->isProduction()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /credentials/integration/webpay-plus-normal/597020000540.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAvuNgBxMAOBlNI7Fw5sHGY1p6DB6EMK83SL4b1ZILSJs/8/MC 3 | X8Pkys3CvJmSIiKU7fnWkgXchEdqXJV+tzgoED/y99tXgoMssi0ma+u9YtPvpT7B 4 | a5rk5HpLuaFNeuE3l+mpkXDZZKFSZJ1fV/Hyn3A1Zz+7+X2qiGrAWWdjeGsIkz4r 5 | uuMFLQVdPVrdAxEWoDRybEUhraQJ1kwmx92HFfRlsbNAmEljG9ngx/+/JLA28cs9 6 | oULy4/M7fVUzioKsBJmjRJd6s4rI2YIDpul6dmgloWgEfzfLNnAsZhJryJNBr2Wb 7 | E6DL5x/U2XQchjishMbDIPjmDgS0HLLMjRCMpQIDAQABAoIBAEkSwa/zliHjjaQc 8 | SRwNEeT2vcHl7LS2XnN6Uy1uuuMQi2rXnBEM7Ii2O9X28/odQuXWvk0n8UKyFAVd 9 | NSTuWmfeEyTO0rEjhfivUAYAOH+coiCf5WtL4FOWfWaSWRaxIJcG2+LRUGc1WlUp 10 | 6VXBSR+/1LGxtEPN13phY0DWUz3FEfGBd4CCPLpzq7HyZWEHUvbaw89xZJSr/Zwh 11 | BDZZyTbuwSHc9X9LlQsbaDuW/EyOMmDvSxmSRJO10FRMxyg8qbE4edtUK4jd61i0 12 | kGFqdDu9sj5k8pDxOsN2F270SMlIwejZ1uunB87w9ezIcR9YLq9aa22cT8BZdOxb 13 | uZ3PAAECgYEA6xfgRtcvpJUBWBVNsxrSg6Ktx2848eQne9NnbWHdZuNjH8OyN7SW 14 | Fn0r4HsTw59/NJ1L5F3co5L5baEtRbRLWRpD72xjrXsQSsoKliCik1xgDIplMvOh 15 | teA2GdeSv9wglqnotGcj5B/8+vn3tEzMjy+UUsyFn0fIaDC3zK3W2qUCgYEAz90g 16 | va+FCcU8cnykb5Yn1u1izdK1c6S++v1bQFf6590ZMNy3p0uGrwAk/MzuBkJ421GK 17 | p4pInUvO/Mb2BCcoHtr3ON3v0DCLl6Ae2Gb7lG0dLgcZ1EK7MDpMvKCqNHAv8Qu8 18 | QBZOA08L8buVkkRt7jxJrPuOFDI5JAaWCmMOSgECgYEA3GvzfZgu9Go862B2DJL+ 19 | hCuYMiCHTM01c/UfyT/z/Y7/ln2+8FniS02rQPtE6ar28tb0nDahM8EPGon/T5ae 20 | +vkUbzy6LKLxAJ501JPeurnm2Hs+LUqe+U8yioJD9p2m9Hx0UglOborLgGm0pRlI 21 | xou+zu8x7ci5D292NXNcun0CgYAVKV378bKJnBrbTPUwpwjHSMOWUK1IaK1IwCJa 22 | GprgoBHAd7f6wCWmC024ruRMntfO/C4xgFKEMQORmG/TXGkpOwGQOIgBme+cMCDz 23 | xwg1xCYEWZS3l1OXRVgqm/C4BfPbhmZT3/FxRMrigUZo7a6DYn/drH56b+KBWGpO 24 | BGegAQKBgGY7Ikdw288DShbEVi6BFjHKDej3hUfsTwncRhD4IAgALzaatuta7JFW 25 | NrGTVGeK/rE6utA/DPlP0H2EgkUAzt8x3N0MuVoBl/Ow7y5sqIQKfEI7h0aRdXH5 26 | ecefOL6iiJWQqX2+237NOd0fJ4E1+BCMu/+HnyCX+cFM2FgoE6tC 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /credentials/integration/webpay-oneclick-normal/597044444405.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA48S877GUtjlYrqIQDlZAMqg5kfNrrZlCZckC1LGzCfcPu7Lm 3 | za2c2F1Q7zKELqVTo1wuZUS1inhYmtg4PexDKak/uryARR3uy2kqq3yG3IQNIdQY 4 | RpAUl8SvNyJvUVtA0N6nwjaqsTv1EacOLsfR+9HNvRXaWSitXNFa7i2G0iN/pnXb 5 | a796mUMVMwJPkV6Si6608566mvqkSnvzulAaC/eev1KIyH5oF22yjyWRIM+K9ZNx 6 | 7Cosnxgmt6e/8AazGBxA7gXxV6DQtOvL6k4AottUro2hMXLUZRS3x4GjtJDUjpLj 7 | UIHpK5Tz66D8dGN+Kv/f/Y7bAWMHUQqrPHkAcQIDAQABAoIBAEEcqeJfwqKBLE/n 8 | 9m0SzRFuM978VmjvKiMM3qlND2Cm5zGCSCa+HdtgedWXfGAVVR6bKIw8oyUtmC7T 9 | 5ugU1XJgdt58KrMXhn9R1ifl1mvNuC9WgYYShECKsogxaN86FgJf1FdZ51v5Ruq/ 10 | 9fb7mpTBem42hA/+5+hj1PnHvAXwI9/erX8nZIixtj9PVJOzUW/izlJVm9DoT2vM 11 | JZAt/HXZqovvsSet5tRfTPTuFH+NTXnfpHbDGPDqQrC+fqTaZCFJXU0lgWemBdM2 12 | HIafstxFhY5cbgYKl6nW8SQNQQUG7ifJ5ttz7jNqZ3X9hk2yIvK+0Dd1NKTlJoAS 13 | 5V8FL00CgYEA96jBRG4I2P0rbQl7Elf5A4xS9ruFgQtS6//9g5ezLmxtiVQhryl4 14 | 4PKKWY1nRPhQBQaQdp6H9w8rU5ccyAFjW4hDfD8jwTCE1On1dSfBWcrBir4LL/Dm 15 | WbOgrh2jotvAmInkl6GohwRZIF77kRQXc+Zv2Xle2o+JMv4keBmuk+sCgYEA63B9 16 | yoV0qhuTnrFNW99rQTQ8WnfUYdmau/4W2CSkNVgZ04j5xKe2FzBkQHnvCDX5THkW 17 | YVsq0J/F3BBApKvKwACVdri19odJRi2JgbJarMZb+xro8kqAZ3KvXkXTYpxkBk7S 18 | hkHBrj6sXe+I3usNN3iH80z6ZTsg2dBU7cp4khMCgYEA0amCBKaKwviBnQubr0ne 19 | vAw96DeUrEyj5LuRKahxvul4Sfx5j8qyVO3ABlRZiuAVDkwiXOmU/alP6rJRYVkb 20 | fk/7oeHqKREkQwPWE1qWq6ek9goxemKdAG+7pevdrnAPupNyfJQVEkiyE1+V5Zp2 21 | yF3bbub7UFiXtB3HTg2f6AUCgYEAt9DQ9TAywKjdHRXyfts1IuhEgqFx2J+LNmEP 22 | ttsMtXU+XLBhyQ7jlME8VDaez/tL00/qkEIccFt9n+20epyBpFwQVWuq7Xn8VGUz 23 | KWZ1ctU/dRIycxCFpb6dem3rtt7BHUenCBkIvSDDdGeSpfBAFmHtSqB8ElMSt9v2 24 | otzkO68CgYBhIDz4rTMuOxmt9yily7rcd9J7RrbC7hPHMjM5EwPyOmawAYjTRM8X 25 | rxe1w4MtKrXxn11EncMJuH0hLQ12MwmrTui7gllTi8IPkfe+e7yhgHzzB5Mnhax0 26 | 92jL5rYiTenvy/wIjmF3TDHwyX6dB6QuozltdYBE2rv/oXOrE19qCQ== 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /credentials/integration/webpay-patpass-normal/597020000548.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEA0t4cnHnAr/05KYwk+2ziYKUAxk/E0LhpG8KSyJp9Kl1G09I8 3 | xBhSnF23XpEm6grgKmxzbGtj8t8u9P54sNxNrcs0tawV0qHfzsS63hAJ1254LeZA 4 | uTVpWXUnEl4DWI9Pq67OWUovUPL/mQzcZBJShspC6zX0unfWRnoDeNtx07aj/xq0 5 | PXXtqOEJhyY6EyRsO9XWPVKIm5ZnVCBg9mtrZZkwwROETlD65meCE6gYC6WFrB5F 6 | UvjS72CnA0ZynFj/Vb4Ymi6Ot5M3f0NmGG9q0kweOQfNyv+e/QoB7KVHLrpMdcKO 7 | 70D+ItPK4wdUlOfbTZJYWUaK6F/z2LkF0APD0QIDAQABAoIBAFrSRZpzqjViqHMn 8 | pGoSLLKZfurrQobvVn4ZYOU7/Pr5L99d5sRDAZnNl4QImq0lQAWlrlUdL/BUhkIJ 9 | NGxghqh7JFm3I7MT+3RwMVghqkt6jhKe4HOk+JoKJmj3yxMirprwcHnuxNBlyQbf 10 | jjEf3yGlDguGssB5ivXR6ZrtUWpwsK9OBiRctSeceFE4r68ldDKRFVLNURkK1AEd 11 | lCbhWp1a8W5CKvPjj6Rpq9r1kmTJA1h9NSkLum4f7aewvFhG6bHWEcjA6EWieipj 12 | 2zk74/1HBDpujHJSUzTcXbiIsOVtY2Qh+74CMzHUUS41dGQNk/l/qUk7tRljwjFm 13 | PerH1FECgYEA6IKDDTbaLNsK4BefqlXZvCXbm0irxCb3XvvcsTqcDyZG0KWOCoXw 14 | B24xrsMfbheR0L6x4JUS6RM4bvTEhK4gJzDDeFhfPj2Kuav9nl1oEOZaJ5rxLlz7 15 | 90g/f6kqjW3qlBVSFtz/jVrAk+lju9piHudwerjLA7TXLLm0tJZf7N0CgYEA6Cvc 16 | HzDhxdNYVakWsTBKI/uOUwt7cbHUr7OfoQA5dTxqHvFKBjrY3rgcI3/4vU3cEwRm 17 | a4X6RRSljyKAel54h4eJndP9+dB3VrOOkvuHXOLEVwwzfdaO+4FRQXR+0i9T46RK 18 | 7FJy6XLfhPwZozebXbSTg/WZJ5UczVmxBYzquYUCgYEAu1t/0wQiZwbTCqS+qnmn 19 | jK9M+SJkFxn3N/joa3/5BVQouDTP8rbfJn2rV1IwX3xqqbUgjQJTTLGKRg7C1M+j 20 | ZTEsMiu0A+l/ggKPyi8mjoewmj2Gn3+aIjd7w5lDitfJsS5FCdtnqjY4/HeTQGrH 21 | qnOA9cM3BHOS+J1keii6f5kCgYEAofbO9bdtGUuJySBPY0azwgxgSlCtSjBrljLx 22 | vihg7Qc7ZOCg6l2tIxo/DwjcZntldqLQLFxnrj9sC8Fe7X7wCGQmPcNA30BtsD9M 23 | y/7KfKL5o1wwo63FS3D4VXhGbKx1kk3vspMF9ROdGLGh1Poa2bD6Y8k2kaV1VVAn 24 | rR6UNN0CgYEAgWw0NRz9X3V5K0WfrXnqBEvDiJ9MnsO3Y0SmV+zbTVYQ2zf2iYT+ 25 | Wp4Tpjfc2k8s1dU33YnsrLaecB3gEFeEHJdN9qOPkk/yElVrcCKfFEUmPu7wvHZI 26 | yCLqC4NXGoXossGlQ2XPCSYacEQ5JJTtv+sBufhJZTwuqEBSGS7PurA= 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /credentials/integration/webpay-plus-capture/597044444404.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEAq62F11DVV2ciL/S/zKr8NmesZNUoI3t/9EbZ5m97LjH/R1s2 3 | 0MxJWjmy0f+I64PvJkGOvQauBdJoGiiCeiV3qY+PppgOQmMo8xXaPzErrVr0F9bx 4 | 3gbqSuqi/uwJNJRWUs3tYmlQ/WQrKHSMxpRkVthWoIpyR3UEBpr9N9MhAdDarJCv 5 | /df9Hyu3RpE7ULFCnCHi/y3DVPYi3TnXa4xo9fE3iVuxMNjCUO93GqETYVCRoIW/ 6 | 237frd8tgZ3biNmYRqbxO6jIv/1uEJs2mxPaW+FmdpW4+yM1tK8e8mWV/OrqpslZ 7 | O0mqUVY16phJJW7ad4fi0V3+TCRwgY0MC6x6uwIDAQABAoIBAQCktQoflXHZNR1b 8 | nRkWp0TqfXSsGMU1pZsRJZiQuIwZueYM87oXgKcvZQPm7Z7TNfUPYv4q5Gm5NDCk 9 | SBFGVwQDLbTIREIJ91CmR2ToE6iv3P8qkBHkzgWicpKGuLXsOBTJxL/nFtuY/61Y 10 | Vtlo+514pH4X8DvLyrxeCfy+vlSAg+mcs+35wnxC+qvAESYXQKODorGljmthkqyd 11 | P/ONKef+PsyJuUevne2YSkiqaDywGBe5JRS+Ij74UH7d+/+hDS9AMwj+nrlVE/Bj 12 | Y1zCw0BijKNuwnoF9oHMZvshfV2GkpS237tmXDbn+fJOqWfonb/CkBtWsF86N79h 13 | /x+gJQ8hAoGBANeQ8/fDA8azfh6z6Ar6C0XIxgZppLtGPac65JhyKCYtvH1kzhJU 14 | dnBqcMOxj9K3zbK3A21Y3gBMZvNS9Wja8Pk7r0R6aHU7eMOlEiOoEdeoVtlOpj4p 15 | Y87Yc8vojd0nnuWJpxw6R8MvzJBm750tIE0/rv2+vfDeaxiWUexhrq0FAoGBAMvh 16 | I5saf9OTJLvBfu8gqldLGdlkG1+1eyxnJbQuHq6o+WsaxjFEwS5a8MOlD7my0tom 17 | zm98fiFHpGX3HGoG9RQuvRKmWRCdj5qb7Bep3gWb9HOKYG+6DKGPPpmJ6fdjV9zh 18 | o5ru5iFJoWHcE60/kVbOJsh6ugVXFzF6DJaBkRS/AoGBAK3Bv4VkgjS2FeD1rwK6 19 | DkAP197vZMM3mRalGAHxcn9jul1w1dJclqOCiKaVB5MYaQu3DWIkkb231/wmUH5W 20 | jIq5G0udR3nHmE5LTlXDca5dmLPM+597iWH/g0dHiqJK/3+R90t/hrzEWKXE8zvE 21 | VhcuUAVkrIHtJnJJKHvbOQtpAoGAXEqPVrAZO0p5r3C5KECOO7PogKs7ZQj/OCt9 22 | OuJBy2j8d0qIe1cXaAeMw9PdmX9kyZIVkww1AJWwyuOg/jImETvTJTUeTlI05pU8 23 | u72OntVpREBYxVrgSuZQPSrcObvD015lNEZ+8ISnRGhek+eZwETT857yxGYXPrN0 24 | LVF7vnsCgYEApWvaUImePJDN50+nExK6TWHGFNnlZPlqFuyEHCSIlC0moGkcdl1D 25 | uILlje5JjmCI6hUreePcpFbyuiWcFcRJPdTgPWAcuWpPqFk3TyMVg8RQjZ4nIb4e 26 | TB3lRTP7u4t4emHHeNZhSeakRMOUYWiylCgSLmmf1OKd/bWTQ6G7lk0= 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /examples/onepay/start.php: -------------------------------------------------------------------------------- 1 | setDefaults('onepay', [ 8 | 'channel' => 'web', 9 | 'generateOttQrCode' => true, 10 | 'callbackUrl' => currentUrlPath('confirm.php'), 11 | ]); 12 | 13 | $onepay = $transbank->onepay(); 14 | 15 | $cart = $onepay->makeCart([ 16 | 'items' => [ 17 | 'description' => 'Producto de Prueba', 18 | 'quantity' => 2, 19 | 'amount' => 9990, 20 | ] 21 | ]); 22 | 23 | $result = $cart->commit(); 24 | ?> 25 | 26 | 27 | 28 | 29 | Conectando con Onepay... 30 | 31 | 32 | 33 |
34 |

Cesta enviada:

35 |
toArray()) ?>
36 |

Respuesta:

37 |
toArray()) ?>
38 |
39 | 40 |

1) Procesar compra de prueba en dashboard

41 |
42 | 46 |
47 |

2) Confirmar compra internamente:

48 |
49 | 50 | 51 |
52 | 53 |
54 |
55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /examples/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Ejemplos de integración de Servicios Transbank 9 | 10 | 11 | 12 | 13 |
14 |

Ejemplos de integración de Servicios Transbank

15 |
16 | Todos estos ejemplos usan las credenciales de integración suministradas por Transbank, así que no es necesario hacer nada más que probar cómo funcionan las transacciones. 17 |
18 | 40 |
41 | 42 | -------------------------------------------------------------------------------- /src/Adapters/AbstractAdapter.php: -------------------------------------------------------------------------------- 1 | client = $client; 39 | } 40 | 41 | /** 42 | * Returns the Client used to communicate with Transbank 43 | * 44 | * @return object 45 | */ 46 | public function getClient() 47 | { 48 | return $this->client; 49 | } 50 | 51 | /** 52 | * Sets credentials to use against Transbank SDK 53 | * 54 | * @param Fluid $credentials 55 | * @return mixed 56 | */ 57 | public function setCredentials(Fluid $credentials) 58 | { 59 | $this->credentials = $credentials; 60 | } 61 | 62 | /** 63 | * Returns if the environment is Production 64 | * 65 | * @return bool 66 | */ 67 | public function isProduction() 68 | { 69 | return $this->isProduction; 70 | } 71 | 72 | /** 73 | * Sets if the the environment is Production 74 | * 75 | * @param bool $isProduction 76 | */ 77 | public function setIsProduction(bool $isProduction) 78 | { 79 | $this->isProduction = $isProduction; 80 | } 81 | } -------------------------------------------------------------------------------- /src/Clients/Webpay/PlusCapture.php: -------------------------------------------------------------------------------- 1 | $transaction->authorizationCode, 31 | 'buyOrder' => $transaction->buyOrder, 32 | 'captureAmount' => $transaction->captureAmount, 33 | 'commerceId' => $transaction->commerceId ?? $this->credentials->commerceCode, 34 | ]; 35 | 36 | try { 37 | // Perform the capture with the data, and return if validates 38 | $response = $this->performCapture($capture); 39 | } catch (Exception $e) { 40 | throw new ErrorResponseException($e->getMessage(), $e->getCode(), $e); 41 | } 42 | 43 | if ($this->validate()) { 44 | return $response; 45 | }; 46 | 47 | throw new InvalidSignatureException(); 48 | } 49 | 50 | /** 51 | * Performs the Webpay Soap Capture operation 52 | * 53 | * @param $capture 54 | * @return array 55 | */ 56 | protected function performCapture($capture) 57 | { 58 | return (array)($this->connector->capture([ 59 | 'captureInput' => $capture 60 | ]))->return; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /tests/Unit/Responses/AbstractResponseTest.php: -------------------------------------------------------------------------------- 1 | response = new class extends AbstractResponse { 16 | protected $tokenName = 'old-token'; 17 | protected $listKey = 'webpay.plus'; 18 | protected $errorCode = -8; 19 | public function dynamicallySetSuccessStatus() 20 | { 21 | $this->isSuccess = true; 22 | } 23 | }; 24 | } 25 | 26 | public function testGetAndSetTokenName() 27 | { 28 | $this->assertEquals('old-token', $this->response->getTokenName()); 29 | $this->response->setTokenName('new-token'); 30 | $this->assertEquals('new-token', $this->response->getTokenName()); 31 | } 32 | 33 | public function testDynamicallySetSuccessStatus() 34 | { 35 | $this->response->dynamicallySetSuccessStatus(); 36 | $this->assertTrue($this->response->isSuccess()); 37 | } 38 | 39 | public function testGetErrorForHumans() 40 | { 41 | $errorCode = 'Rubro no autorizado.'; 42 | 43 | $this->assertEquals($errorCode, $this->response->getErrorForHumans()); 44 | } 45 | 46 | public function testSuccess() 47 | { 48 | $this->response->dynamicallySetSuccessStatus(); 49 | 50 | $this->assertTrue($this->response->isSuccess()); 51 | $this->assertFalse($this->response->isFailed()); 52 | } 53 | 54 | public function testGetAndSetType() 55 | { 56 | $this->response->setType('mock-type'); 57 | $this->assertEquals('mock-type', $this->response->getType()); 58 | } 59 | 60 | public function testGetErrorCode() 61 | { 62 | $this->assertEquals(-8, $this->response->getErrorCode()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/TransactionFactories/AbstractTransactionFactory.php: -------------------------------------------------------------------------------- 1 | service = $service; 32 | $this->defaults = $defaults; 33 | } 34 | 35 | /** 36 | * Returns an instance of a Transaction 37 | * 38 | * @param string $type 39 | * @param array $attributes 40 | * @return AbstractTransaction 41 | */ 42 | abstract protected function makeTransaction(string $type, array $attributes = []); 43 | 44 | /** 45 | * Injects Service, Defaults and Type to the Transaction 46 | * 47 | * @param string $type 48 | * @param AbstractTransaction $transaction 49 | * @return AbstractTransaction 50 | */ 51 | protected function prepareTransaction(string $type, AbstractTransaction $transaction) 52 | { 53 | // The Type of the transaction, so the Adapter can differentiate how 54 | // to commit it to Transbank if there is more than one. 55 | $transaction->setType($type); 56 | 57 | // Setting the services allows to commit it using the Service's Adapter. 58 | $transaction->setService($this->service); 59 | 60 | // If it has defaults, they will be appended 61 | $transaction->setDefaults($this->defaults); 62 | 63 | return $transaction; 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /src/Contracts/TransactionInterface.php: -------------------------------------------------------------------------------- 1 | 'bar', 16 | 'baz' => 'qux', 17 | 'quuz' => 'quux', 18 | ]; 19 | 20 | $only = Helpers::arrayOnly($array, ['baz', 'quuz']); 21 | 22 | $this->assertArrayHasKey('baz', $only); 23 | $this->assertArrayHasKey('quuz', $only); 24 | $this->assertArrayNotHasKey('foo', $only); 25 | } 26 | 27 | public function testClassBasename() 28 | { 29 | $name = Helpers::classBasename(self::class); 30 | 31 | $this->assertEquals('HelpersTest', $name); 32 | 33 | $name = Helpers::classBasename('anything'); 34 | 35 | $this->assertNull($name); 36 | } 37 | 38 | public function testArrayExcept() 39 | { 40 | $array = [ 41 | 'foo' => 'bar', 42 | 'baz' => 'qux', 43 | 'quuz' => 'quux', 44 | ]; 45 | 46 | $except = Helpers::arrayExcept($array, ['foo']); 47 | 48 | $this->assertArrayNotHasKey('foo', $except); 49 | $this->assertArrayHasKey('baz', $except); 50 | $this->assertArrayHasKey('quuz', $except); 51 | } 52 | 53 | public function testDirContents() 54 | { 55 | $contents = Helpers::dirContents(__DIR__); 56 | 57 | $this->assertIsArray($contents); 58 | $this->assertTrue(in_array('HelpersTest.php', $contents)); 59 | } 60 | 61 | public function testIsNumericArray() 62 | { 63 | $arrayNumeric = [ 64 | 'foo', 'bar', 'baz' 65 | ]; 66 | 67 | $arrayNotNumeric = [ 68 | 'foo' => 'bar', 69 | 'baz' => 'qux', 70 | 'quuz' => 'quux', 71 | ]; 72 | 73 | $this->assertTrue(Helpers::isNumericArray($arrayNumeric)); 74 | $this->assertFalse(Helpers::isNumericArray($arrayNotNumeric)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Clients/Webpay/SoapImplementation.php: -------------------------------------------------------------------------------- 1 | privateKey = $privateKey; 48 | $this->publicCert = $publicCert; 49 | 50 | parent::__construct($wsdl, $options); 51 | } 52 | 53 | /** 54 | * Makes a Request and validates it 55 | * 56 | * @param string $request 57 | * @param string $location 58 | * @param string $saction 59 | * @param int $version 60 | * @param null $one_way 61 | * @return string 62 | */ 63 | public function __doRequest($request, $location, $saction, $version, $one_way = null) 64 | { 65 | $process = new Process($request); 66 | $process->sign($this->privateKey); 67 | $process->addIssuer($this->publicCert); 68 | $signedRequest = $process->getXML(); 69 | 70 | $retVal = parent::__doRequest( 71 | $signedRequest, 72 | $location, 73 | $saction, 74 | $version, 75 | $one_way 76 | ); 77 | 78 | $doc = new DOMDocument(); 79 | $doc->loadXML($retVal); 80 | return $doc->saveXML(); 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /tests/Unit/Transactions/Concerns/HasSecretsTest.php: -------------------------------------------------------------------------------- 1 | fluent = new class extends Fluid { 19 | use HasSecrets; 20 | protected $attributes = [ 21 | 'foo' => 'bar', 22 | 'baz' => 'qux' 23 | ]; 24 | 25 | public function toArray() 26 | { 27 | if ($this->hideSecrets) { 28 | return Helpers::arrayExcept($this->attributes, ['foo']); 29 | } 30 | return $this->attributes; 31 | } 32 | }; 33 | } 34 | 35 | public function testHideSecrets() 36 | { 37 | $this->fluent->hideSecrets(); 38 | $this->assertTrue($this->fluent->isHidingSecrets()); 39 | $this->fluent->showSecrets(); 40 | $this->assertFalse($this->fluent->isHidingSecrets()); 41 | } 42 | 43 | public function testManipulatesSerialization() 44 | { 45 | $this->fluent->hideSecrets(); 46 | 47 | $this->assertEquals('bar', $this->fluent->foo); 48 | $this->assertEquals('qux', $this->fluent->baz); 49 | $this->assertStringNotContainsString('bar', $this->fluent->toJson()); 50 | $this->assertStringContainsString('qux', $this->fluent->toJson()); 51 | $this->assertArrayNotHasKey('foo', $this->fluent->toArray()); 52 | $this->assertArrayHasKey('baz', $this->fluent->toArray()); 53 | 54 | $this->fluent->showSecrets(); 55 | 56 | $this->assertEquals('bar', $this->fluent->foo); 57 | $this->assertEquals('qux', $this->fluent->baz); 58 | $this->assertStringContainsString('bar', $this->fluent->toJson()); 59 | $this->assertStringContainsString('qux', $this->fluent->toJson()); 60 | $this->assertArrayHasKey('foo', $this->fluent->toArray()); 61 | $this->assertArrayHasKey('baz', $this->fluent->toArray()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/Unit/Transactions/WebpayMallTransactionTest.php: -------------------------------------------------------------------------------- 1 | $items = [ 17 | ['foo' => 'bar'], 18 | ['baz' => 'qux'] 19 | ] 20 | ]); 21 | 22 | foreach ($items as &$item) { 23 | $item = new Item(array_merge($item, ['sessionId' => null])); 24 | } 25 | 26 | $this->assertEquals($items, $transaction->getItems()); 27 | } 28 | 29 | public function testToArray() 30 | { 31 | $transaction = new WebpayMallTransaction([ 32 | 'items' => $items = [ 33 | ['foo' => 'bar'], 34 | ['baz' => 'qux'] 35 | ] 36 | ]); 37 | 38 | $this->assertCount(2, $transaction->getItems()); 39 | $this->assertEquals('bar', $transaction->getItem(0)->foo); 40 | $this->assertEquals('qux', $transaction->getItem(1)->baz); 41 | } 42 | 43 | public function testCallsOrderMethodAsItems() 44 | { 45 | $transaction = new WebpayMallTransaction([ 46 | 'items' => [ 47 | ['foo' => 'bar'], 48 | ['baz' => 'qux'] 49 | ] 50 | ]); 51 | 52 | $transaction->addOrder([ 53 | 'quux' => 'quuz' 54 | ]); 55 | 56 | $this->assertCount(3, $transaction->getOrders()); 57 | $this->assertEquals('bar', $transaction->getOrder(0)->foo); 58 | $this->assertEquals('qux', $transaction->getOrder(1)->baz); 59 | $this->assertEquals('quuz', $transaction->getOrder(2)->quux); 60 | } 61 | 62 | public function testExceptionOnCallingInvalidMethod() 63 | { 64 | $this->expectException(BadMethodCallException::class); 65 | 66 | $transaction = new WebpayMallTransaction([ 67 | 'items' => [ 68 | ['foo' => 'bar'], 69 | ['baz' => 'qux'] 70 | ] 71 | ]); 72 | 73 | $transaction->anything(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Transactions/WebpayTransaction.php: -------------------------------------------------------------------------------- 1 | type) { 17 | case 'plus.normal': 18 | case 'plus.defer': 19 | $defaults = $this->filterDefaults( 20 | 'plus', ['plusReturnUrl', 'plusFinalUrl'], $defaults 21 | ); 22 | break; 23 | case 'plus.mall.normal': 24 | case 'plus.mall.defer': 25 | $defaults = $this->filterDefaults( 26 | 'plusMall', ['plusMallReturnUrl', 'plusMallFinalUrl'], $defaults 27 | ); 28 | break; 29 | case 'oneclick.register': 30 | $defaults = $this->filterDefaults( 31 | 'oneclick', ['oneclickResponseURL'], $defaults 32 | ); 33 | break; 34 | default: 35 | $defaults = []; 36 | break; 37 | } 38 | 39 | parent::setDefaults($defaults); 40 | } 41 | 42 | /** 43 | * Filter the defaults for the Transaction type 44 | * 45 | * @param string $service 46 | * @param array $only 47 | * @param array $defaults 48 | * @return array 49 | */ 50 | protected function filterDefaults(string $service, array $only, array $defaults) 51 | { 52 | foreach (Helpers::arrayOnly($defaults, $only) as $name => $default) { 53 | $result[lcfirst(str_replace($service, '', $name))] = $default; 54 | } 55 | return $result ?? []; 56 | } 57 | 58 | /** 59 | * Fills Empty Attributes 60 | */ 61 | protected function fillEmptyAttributes() 62 | { 63 | // Create the BuyOder with the required timestamp only when this 64 | // transaction is a Webpay Oneclick Charge. 65 | if ($this->type === 'oneclick.charge' && strlen((string)$this->buyOrder) < 14) { 66 | $this->buyOrder = date('YmdHis') . (substr((string)$this->buyOrder, -3) ?? '000'); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/Helpers/Helpers.php: -------------------------------------------------------------------------------- 1 | getShortName(); 21 | } catch (ReflectionException $e) { 22 | return null; 23 | } 24 | } 25 | 26 | /** 27 | * Return the directory contents without dots directories. 28 | * 29 | * @param string $directory 30 | * @return array|null 31 | */ 32 | public static function dirContents(string $directory) 33 | { 34 | try { 35 | return array_values(array_diff(scandir($directory), array('.', '..'))); 36 | } catch (Throwable $throwable) { 37 | return null; 38 | } 39 | } 40 | 41 | /** 42 | * Returns if the array is an untouched numeric index 43 | * 44 | * @param array $array 45 | * @return bool 46 | */ 47 | public static function isNumericArray(array $array) 48 | { 49 | return array_keys($array) === range(0, count($array) - 1); 50 | } 51 | 52 | /** 53 | * Filter an array by the given array keys 54 | * 55 | * @param array $array 56 | * @param string|array $keys 57 | * @return array 58 | */ 59 | public static function arrayOnly(array $array, $keys) 60 | { 61 | return array_intersect_key($array, array_flip((array)$keys)); 62 | } 63 | 64 | /** 65 | * Returns the $array without 66 | * 67 | * @param array $array 68 | * @param $excluded 69 | * @return array 70 | */ 71 | public static function arrayExcept(array $array, $excluded) 72 | { 73 | return array_diff_key($array, array_flip($excluded)); 74 | } 75 | 76 | /** 77 | * Returns the first item in the array. 78 | * 79 | * @param array $array 80 | * @param mixed $default 81 | * @return mixed 82 | */ 83 | public static function arrayFirst(array $array, $default = null) 84 | { 85 | foreach ($array as $item) { 86 | return $item; 87 | } 88 | 89 | return $default; 90 | } 91 | } -------------------------------------------------------------------------------- /src/Concerns/HasCredentialOperations.php: -------------------------------------------------------------------------------- 1 | transbankConfig->getCredentials( 24 | lcfirst(Helpers::classBasename(static::class)) 25 | ); 26 | } 27 | 28 | /** 29 | * Returns the credentials directory for the active environment 30 | * 31 | * @return string 32 | */ 33 | public function environmentCredentialsDirectory() 34 | { 35 | return $this->credentialsDirectory() . '/' . $this->transbankConfig->getEnvironment() . '/'; 36 | } 37 | 38 | /** 39 | * Set the correct credentials in the adapter. 40 | * 41 | * Whe using `integration` environments, Credentials may depend on the 42 | * transaction type being used, so the type is passed to the method. 43 | * After that, these are overridden by any of the user credentials. 44 | * 45 | * @param string|null $type 46 | */ 47 | protected function setAdapterCredentials(string $type = null) 48 | { 49 | $this->adapter->setCredentials( 50 | new Fluid( 51 | array_merge( 52 | $this->isProduction() 53 | ? $this->getProductionCredentials() 54 | : $this->getIntegrationCredentials($type), 55 | (array)$this->credentials ?? [] 56 | ) 57 | ) 58 | ); 59 | } 60 | 61 | /** 62 | * Get the Service Credentials for the Production Environment 63 | * 64 | * @return array 65 | */ 66 | abstract protected function getProductionCredentials(); 67 | 68 | /** 69 | * Get the Service Credentials for the Integration Environment 70 | * 71 | * @param string $type 72 | * @return array 73 | */ 74 | abstract protected function getIntegrationCredentials(string $type = null); 75 | } -------------------------------------------------------------------------------- /src/Clients/Webpay/PlusNullify.php: -------------------------------------------------------------------------------- 1 | $transaction->authorizationCode, 39 | // Authorized Transaction amount to null (substract), or full Capture Amount 40 | 'authorizedAmount' => $transaction->authorizedAmount, 41 | 'buyOrder' => $transaction->buyOrder, 42 | 'commerceId' => $transaction->commerceCode ?? $this->credentials->commerceCode, 43 | 'nullifyAmount' => $transaction->nullifyAmount 44 | ]; 45 | 46 | try { 47 | // Perform the capture with the data, and return if validates 48 | $response = $this->performNullify($transaction); 49 | } catch (Exception $e) { 50 | throw new ErrorResponseException($e->getMessage(), $e->getCode(), $e); 51 | } 52 | 53 | if ($this->validate()) { 54 | return $response; 55 | } 56 | 57 | throw new InvalidSignatureException(); 58 | 59 | } 60 | 61 | /** 62 | * Performs the Nullify on Webpay 63 | * 64 | * @param $transaction 65 | * @return mixed 66 | */ 67 | protected function performNullify($transaction) 68 | { 69 | return (array)($this->connector->nullify([ 70 | 'nullificationInput' => $transaction 71 | ]))->return; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/Contracts/ServiceInterface.php: -------------------------------------------------------------------------------- 1 | 'Resultado exitoso.', 5 | 'CANCELLED_BY_USER' => 'Transacción abortada o no pagada por el usuario.', 6 | 'COMMERCE_NOT_FOUND' => 'El comercio no existe.', 7 | 'ILCAT_ERROR' => 'Error desconocido de Onepay en Transbank.', 8 | 'ILCAT_RESPONSE_ERROR' => 'Error durante la respuesta de Transbank.', 9 | 'ILCAT_SERVICE_ERROR' => 'Error interno del Onepay en Transbank.', 10 | 'INVALID_APP_KEY' => 'App Key (código del lenguage de la librería) inválido.', 11 | 'INVALID_NULLIFY_AMOUNT' => 'El monto a anular no coincide con el de la transacción.', 12 | 'INVALID_PARAMS' => 'Los parámetros de la transacción son incorrectos.', 13 | 'INVALID_PLUGIN_VERSION' => 'Versión inválida, antigua, o no-existente, del plugin.', 14 | 'INVALID_TRANSACTION' => 'El Carro de Compra posee montos o cantidades inválidos, o la transacción no está autorizada y no se puede anular o confirmar.', 15 | 'INVALID_TRANSACTION_SIGN' => 'La firma (signature) de la transacción es inválida.', 16 | 'INVALID_TRANSACTION_STATUS' => 'El estado de la transacción no es válida o autorizada y no se puede confirmar.', 17 | 'INVALID_USER' => 'El usuario o cliente de Onepay es inválido.', 18 | 'ERROR' => 'Error desconocido de Transbank.', 19 | 'FAILED_REVERSE_NULLIFY' => 'La reversa de la transacción falló.', 20 | 'NONEXISTENT_TRANSACTION' => 'La transacción no fue encontrada.', 21 | 'NONEXISTENT_USER' => 'El usuario o cliente de Onepay no existe.', 22 | 'NOT_ACTIVE_COMMERCE' => 'El comercio para esta transacción no está activa.', 23 | 'NULLIFICATION_PERIOD_HAS_EXPIRED' => 'El período para anular la transacción expiró.', 24 | 'ONE_PAY_NOT_INSTALLED' => 'La aplicación de Onepay no está instalado.', 25 | 'REJECTED' => 'Transacción rechazada por el medio de pago o autorizador.', 26 | 'REVERSE_NOT_COMPLETE' => 'La reversa falló por razones desconocidas.', 27 | 'REVERSED' => 'Transacción reversada internamente ante la ausencia de confirmación.', 28 | 'REVERSED_NULLIFY' => 'La reversa de la anulación de la transacción ya fue hecha.', 29 | 'SIGN_VALIDATION_ERROR' => 'La validación de la firma (signature) es inválida.', 30 | 'TRANSACTION_ALREADY_EXISTS' => 'El "externalUniqueNumber" ya fue usado previamente.', 31 | ]; -------------------------------------------------------------------------------- /tests/Unit/Services/OnepayTest.php: -------------------------------------------------------------------------------- 1 | mockTransbank = \Mockery::mock(Transbank::class); 33 | 34 | $this->mockTransbank->shouldReceive('getDefaults') ->once() 35 | ->andReturn([ 'foo' => 'bar' ]); 36 | 37 | $this->mockTransbank->shouldReceive('getCredentials') ->once() 38 | ->andReturn([ 'baz' => 'qux' ]); 39 | 40 | $this->mockAdapter = \Mockery::mock(OnepayAdapter::class); 41 | 42 | $this->mockAdapter->shouldReceive('setCredentials') 43 | ->andReturn(['foo' => 'bar']); 44 | 45 | $this->mockLogger = \Mockery::mock(LoggerInterface::class); 46 | 47 | $this->onepay = new Onepay($this->mockTransbank, $this->mockLogger); 48 | 49 | $this->onepay->setAdapter($this->mockAdapter); 50 | } 51 | 52 | public function testGetTransaction() 53 | { 54 | $this->mockTransbank->shouldReceive('isProduction')->once() 55 | ->andReturnTrue(); 56 | 57 | $this->mockAdapter->shouldReceive('retrieveAndConfirm') 58 | ->andReturn(['foo' => 'bar']); 59 | 60 | $this->mockLogger->shouldReceive('info') 61 | ->with(\Mockery::type('string')) 62 | ->andReturnNull(); 63 | 64 | $transaction = $this->onepay->getTransaction(['mock.transaction']); 65 | 66 | $this->assertInstanceOf(OnepayResponse::class, $transaction); 67 | $this->assertEquals('bar', $transaction->foo); 68 | 69 | $this->mockTransbank->shouldReceive('isProduction')->once() 70 | ->andReturnFalse(); 71 | 72 | $transaction = $this->onepay->getTransaction(['mock.transaction']); 73 | 74 | $this->assertInstanceOf(OnepayResponse::class, $transaction); 75 | $this->assertEquals('bar', $transaction->foo); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/Unit/Adapters/OnepayAdapterTest.php: -------------------------------------------------------------------------------- 1 | adapter = new OnepayAdapter(); 29 | 30 | $this->client = \Mockery::mock(AbstractClient::class, [ 31 | true, new Fluid(['foo' => 'bar']) 32 | ]); 33 | 34 | $this->adapter->setClient($this->client); 35 | } 36 | 37 | public function testCommit() 38 | { 39 | $this->client->allows([ 40 | 'commit' => true, 41 | 'refund' => true, 42 | ]); 43 | 44 | $transaction = new OnepayTransaction([ 'foo' => 'bar' ]); 45 | $transaction->setType('onepay.cart'); 46 | $response = $this->adapter->commit($transaction); 47 | $this->assertTrue($response); 48 | 49 | $transaction = new OnepayNullifyTransaction([ 'foo' => 'bar' ]); 50 | $transaction->setType('onepay.nullify'); 51 | $response = $this->adapter->commit($transaction); 52 | $this->assertTrue($response); 53 | } 54 | 55 | public function testDoesntInstancesClientAgain() 56 | { 57 | $client = \Mockery::mock('overload:' . OnepayClient::class); 58 | 59 | $client->expects('boot'); 60 | $client->shouldReceive('commit')->andReturnTrue(); 61 | 62 | $this->adapter->setClient(null); 63 | 64 | $transaction = new OnepayTransaction([ 'foo' => 'bar' ]); 65 | $transaction->setType('onepay.cart'); 66 | $response = $this->adapter->commit($transaction); 67 | $this->assertTrue($response); 68 | } 69 | 70 | public function testNullOnCommitUnavailable() 71 | { 72 | $transaction = new OnepayTransaction([ 'foo' => 'bar' ]); 73 | $transaction->setType('anthing'); 74 | $response = $this->adapter->commit($transaction); 75 | $this->assertNull($response); 76 | } 77 | 78 | public function testRetrieveAndConfirm() 79 | { 80 | $this->client->allows([ 81 | 'confirm' => true, 82 | ]); 83 | 84 | $response = $this->adapter->retrieveAndConfirm(['transaction']); 85 | $this->assertTrue($response); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/TransactionFactories/OnepayTransactionFactory.php: -------------------------------------------------------------------------------- 1 | prepareTransaction($type, new OnepayNullifyTransaction($attributes)); 24 | case 'onepay.cart': 25 | default: 26 | return $this->prepareTransaction($type, new OnepayTransaction($attributes)); 27 | } 28 | } 29 | 30 | /** 31 | * Makes a Onepay Transaction, optionally with Items inside it 32 | * 33 | * @param array $attributes 34 | * @return \DarkGhostHunter\TransbankApi\Transactions\AbstractTransaction 35 | * @return OnepayTransaction 36 | * @throws \Exception 37 | */ 38 | public function makeCart(array $attributes = []) 39 | { 40 | return $this->makeTransaction('onepay.cart', $attributes); 41 | } 42 | 43 | /** 44 | * Creates a Onepay Transaction and immediately sends it to Transbank 45 | * 46 | * @param array $attributes 47 | * @return \DarkGhostHunter\TransbankApi\Responses\AbstractResponse 48 | * @return OnepayTransaction 49 | * @throws \Exception 50 | */ 51 | public function createCart(array $attributes) 52 | { 53 | return $this->makeCart($attributes)->commit(); 54 | } 55 | 56 | /** 57 | * Creates a new Onepay Nullify transaction 58 | * 59 | * @param array $attributes 60 | * @return \DarkGhostHunter\TransbankApi\Transactions\AbstractTransaction&OnepayNullifyTransaction 61 | * @return OnepayTransaction 62 | * @throws \Exception 63 | */ 64 | public function makeNullify(array $attributes) 65 | { 66 | return $this->makeTransaction('onepay.nullify', $attributes); 67 | } 68 | 69 | /** 70 | * Creates a Onepay Nullify transaction and immediately sends it to Transbank 71 | * 72 | * @param array $attributes 73 | * @return \DarkGhostHunter\TransbankApi\Responses\AbstractResponse 74 | * @return \DarkGhostHunter\TransbankApi\Responses\OnepayResponse 75 | * @throws \Exception 76 | */ 77 | public function createNullify(array $attributes) 78 | { 79 | return $this->makeNullify($attributes)->commit(); 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /tests/Unit/Transactions/AbstractTransactionTest.php: -------------------------------------------------------------------------------- 1 | mockService = \Mockery::mock(AbstractService::class); 21 | 22 | $this->transaction = new class extends AbstractTransaction {}; 23 | } 24 | 25 | public function testGetAndSetService() 26 | { 27 | $this->transaction->setService($this->mockService); 28 | 29 | $this->assertInstanceOf(AbstractService::class, $this->transaction->getService()); 30 | } 31 | 32 | public function testGetAndSetType() 33 | { 34 | $this->transaction->setType('test-type'); 35 | 36 | $this->assertEquals('test-type', $this->transaction->getType()); 37 | } 38 | 39 | public function testCommit() 40 | { 41 | $this->mockService->shouldReceive('commit')->once() 42 | ->with($this->transaction) 43 | ->andReturn($array = ['foo' => 'bar']); 44 | 45 | $this->transaction->setService($this->mockService); 46 | 47 | $response = $this->transaction->commit(); 48 | 49 | $this->assertEquals($array, $response); 50 | } 51 | 52 | public function testSingleCommit() 53 | { 54 | $this->mockService->shouldReceive('commit')->once() 55 | ->with($this->transaction) 56 | ->andReturn($array = ['foo' => 'bar']); 57 | 58 | $this->transaction->setService($this->mockService); 59 | 60 | $this->transaction->commit(); 61 | 62 | $response = $this->transaction->commit(); 63 | 64 | $this->assertEquals($array, $response); 65 | } 66 | 67 | public function testForceCommit() 68 | { 69 | $this->mockService->shouldReceive('commit')->twice() 70 | ->with($this->transaction) 71 | ->andReturn($array = ['foo' => 'bar']); 72 | 73 | $this->transaction->setService($this->mockService); 74 | 75 | $response = $this->transaction->commit(); 76 | 77 | $forcedResponse = $this->transaction->forceCommit(); 78 | 79 | $this->assertEquals($array, $response); 80 | $this->assertEquals($array, $forcedResponse); 81 | } 82 | 83 | public function testSetDefaults() 84 | { 85 | $this->transaction->baz = 'qux'; 86 | $this->transaction->quux = 'quuz'; 87 | 88 | $this->transaction->setDefaults([ 89 | 'foo' => 'bar', 90 | 'quux' => 'notQuuz' 91 | ]); 92 | 93 | $this->assertEquals('bar', $this->transaction->foo); 94 | $this->assertEquals('qux', $this->transaction->baz); 95 | $this->assertEquals('quuz', $this->transaction->quux); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Concerns/HasServiceGettersAndSetters.php: -------------------------------------------------------------------------------- 1 | transbankConfig->isProduction(); 26 | } 27 | 28 | /** 29 | * Returns if the service is using an Integration environment 30 | * 31 | * @return bool 32 | */ 33 | public function isIntegration() 34 | { 35 | return $this->transbankConfig->isIntegration(); 36 | } 37 | 38 | /** 39 | * Retrieves the default options for the service Transactions 40 | * 41 | * @return array|null 42 | */ 43 | protected function getDefaults() 44 | { 45 | return $this->transbankConfig->getDefaults( 46 | lcfirst(Helpers::classBasename(static::class)) 47 | ) ?? []; 48 | } 49 | 50 | /** 51 | * Get the Adapter 52 | * 53 | * @return AdapterInterface 54 | */ 55 | public function getAdapter() 56 | { 57 | return $this->adapter; 58 | } 59 | 60 | /** 61 | * Set the Adapter 62 | * 63 | * @param AdapterInterface $adapter 64 | */ 65 | public function setAdapter(AdapterInterface $adapter) 66 | { 67 | $this->adapter = $adapter; 68 | } 69 | 70 | /** 71 | * Get the Transaction Factory 72 | * 73 | * @return string 74 | */ 75 | public function getTransactionFactory() 76 | { 77 | return $this->transactionFactory; 78 | } 79 | 80 | /** 81 | * Set the Transaction Factory 82 | * 83 | * @param AbstractTransactionFactory $transactionFactory 84 | */ 85 | public function setTransactionFactory(AbstractTransactionFactory $transactionFactory) 86 | { 87 | $this->transactionFactory = $transactionFactory; 88 | } 89 | 90 | /** 91 | * Get the Response Factory 92 | * 93 | * @return string 94 | */ 95 | public function getResponseFactory() 96 | { 97 | return $this->responseFactory; 98 | } 99 | 100 | /** 101 | * Set the Response Factory 102 | * 103 | * @param AbstractResponseFactory $responseFactory 104 | */ 105 | public function setResponseFactory(AbstractResponseFactory $responseFactory) 106 | { 107 | $this->responseFactory = $responseFactory; 108 | } 109 | } -------------------------------------------------------------------------------- /tests/Unit/Transactions/WebpayTransactionTest.php: -------------------------------------------------------------------------------- 1 | 'http://app.com/webpay/return', 16 | 'plusFinalUrl' => 'http://app.com/webpay/final', 17 | 'plusMallReturnUrl' => 'http://app.com/webpay/mall/return', 18 | 'plusMallFinalUrl' => 'http://app.com/webpay/mall/final', 19 | 'oneclickResponseURL' => 'http://app.com/webpay/response', 20 | ]; 21 | 22 | protected function setUp() : void 23 | { 24 | $this->transaction = new WebpayTransaction(); 25 | } 26 | 27 | public function testSetsDefaultsForPlusNormal() 28 | { 29 | $this->transaction->setType('plus.normal'); 30 | 31 | $this->transaction->setDefaults($this->defaults); 32 | 33 | $this->assertEquals('http://app.com/webpay/return', $this->transaction->returnUrl); 34 | $this->assertEquals('http://app.com/webpay/final', $this->transaction->finalUrl); 35 | $this->assertCount(2, $this->transaction->getAttributes()); 36 | } 37 | 38 | public function testSetsDefaultsForPlusDefer() 39 | { 40 | $this->transaction->setType('plus.defer'); 41 | 42 | $this->transaction->setDefaults($this->defaults); 43 | 44 | $this->assertEquals('http://app.com/webpay/return', $this->transaction->returnUrl); 45 | $this->assertEquals('http://app.com/webpay/final', $this->transaction->finalUrl); 46 | $this->assertCount(2, $this->transaction->getAttributes()); 47 | } 48 | 49 | public function testSetsDefaultsForPlusMallNormal() 50 | { 51 | $this->transaction->setType('plus.mall.normal'); 52 | 53 | $this->transaction->setDefaults($this->defaults); 54 | 55 | $this->assertEquals('http://app.com/webpay/mall/return', $this->transaction->returnUrl); 56 | $this->assertEquals('http://app.com/webpay/mall/final', $this->transaction->finalUrl); 57 | $this->assertCount(2, $this->transaction->getAttributes()); 58 | } 59 | 60 | public function testSetsDefaultsForPlusMallDefer() 61 | { 62 | $this->transaction->setType('plus.mall.defer'); 63 | 64 | $this->transaction->setDefaults($this->defaults); 65 | 66 | $this->assertEquals('http://app.com/webpay/mall/return', $this->transaction->returnUrl); 67 | $this->assertEquals('http://app.com/webpay/mall/final', $this->transaction->finalUrl); 68 | $this->assertCount(2, $this->transaction->getAttributes()); 69 | } 70 | 71 | public function testSetsDefaultsForOneclickRegister() 72 | { 73 | $this->transaction->setType('oneclick.register'); 74 | 75 | $this->transaction->setDefaults($this->defaults); 76 | 77 | $this->assertEquals('http://app.com/webpay/response', $this->transaction->responseURL); 78 | $this->assertCount(1, $this->transaction->getAttributes()); 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/Adapters/OnepayAdapter.php: -------------------------------------------------------------------------------- 1 | client) { 27 | $this->client = new OnepayClient($this->isProduction, $this->credentials); 28 | $this->client->boot(); 29 | } 30 | } 31 | 32 | /** 33 | * Commits a transaction into the Transbank SDK 34 | * 35 | * @param TransactionInterface|\DarkGhostHunter\TransbankApi\Transactions\OnepayTransaction|\DarkGhostHunter\TransbankApi\Transactions\OnepayNullifyTransaction $transaction 36 | * @param mixed|null $options 37 | * @return array 38 | * @throws \Exception 39 | */ 40 | public function commit(TransactionInterface $transaction, $options = null) 41 | { 42 | $this->bootClient(); 43 | 44 | switch ($transaction->getType()) { 45 | case 'onepay.cart': 46 | return $this->commitCart($transaction); 47 | case 'onepay.nullify': 48 | return $this->commitNullify($transaction); 49 | } 50 | } 51 | 52 | /** 53 | * Commits a Onepay Cart 54 | * 55 | * @param OnepayTransaction $transaction 56 | * @return array 57 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\Onepay\OnepayValidationException 58 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\Onepay\OnepayClientException 59 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\Onepay\OnepayResponseException 60 | */ 61 | protected function commitCart(OnepayTransaction $transaction) 62 | { 63 | return $this->client->commit($transaction); 64 | } 65 | 66 | /** 67 | * Commits a Nullify transaction 68 | * 69 | * @param OnepayNullifyTransaction $transaction 70 | * @return array 71 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\Onepay\OnepayClientException 72 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\Onepay\OnepayResponseException 73 | */ 74 | protected function commitNullify(OnepayNullifyTransaction $transaction) 75 | { 76 | return $this->client->refund($transaction); 77 | } 78 | 79 | /** 80 | * Retrieves and Acknowledges a transaction into the Transbank SDK 81 | * 82 | * @param $transaction 83 | * @param mixed|null $options 84 | * @return mixed 85 | * @throws \Exception 86 | */ 87 | public function retrieveAndConfirm($transaction, $options = null) 88 | { 89 | $this->bootClient(); 90 | 91 | return $this->client->confirm(new OnepayTransaction($transaction)); 92 | } 93 | } -------------------------------------------------------------------------------- /tests/Feature/Integration/OnepayIntegrationTransactionsTest.php: -------------------------------------------------------------------------------- 1 | setDefaults('onepay', [ 23 | 'channel' => 'mobile', 24 | 'generateOttQrCode' => true, 25 | 'callbackUrl' => 'http://app.com/onepay/result', 26 | 'appScheme' => 'my-app://onepay/result', 27 | ]); 28 | 29 | $this->onepay = Onepay::fromConfig($transbank); 30 | } 31 | 32 | public function testCreatesCartInTransbank() 33 | { 34 | $cart = $this->onepay->createCart([ 35 | 'channel' => 'web', 36 | 'items' => [ 37 | 'description' => 'Zapatos', 38 | 'quantity' => 1, 39 | 'amount' => 15000 40 | ] 41 | ]); 42 | 43 | $this->assertTrue($cart->isSuccess()); 44 | $this->assertNotEmpty($cart->ott); 45 | $this->assertNotEmpty($cart->externalUniqueNumber); 46 | $this->assertNotEmpty($cart->qrCodeAsBase64); 47 | $this->assertNotEmpty($cart->issuedAt); 48 | $this->assertNotEmpty($cart->signature); 49 | } 50 | 51 | public function testExceptionOnChannelAppWithoutScheme() 52 | { 53 | $this->expectException(OnepayResponseException::class); 54 | 55 | $this->onepay->createCart([ 56 | 'channel' => 'app', 57 | 'appScheme' => null, 58 | 'items' => [ 59 | 'description' => 'Zapatos', 60 | 'quantity' => 1, 61 | 'amount' => 15000 62 | ] 63 | ]); 64 | } 65 | 66 | public function testCreatedCartHidesSignatureOnSerialization() 67 | { 68 | $cart = $this->onepay->createCart([ 69 | 'items' => [ 70 | 'description' => 'Zapatos', 71 | 'quantity' => 1, 72 | 'amount' => 15000 73 | ] 74 | ]); 75 | 76 | $this->assertFalse(strpos($cart->toJson(), 'signature')); 77 | $this->assertFalse(strpos((string)$cart, 'signature')); 78 | } 79 | 80 | public function testExceptionOnCartWithZeroAmount() 81 | { 82 | $this->expectException(CartNegativeAmountException::class); 83 | 84 | $cart = $this->onepay->createCart([ 85 | 'items' => [ 86 | 'description' => 'Zapatos', 87 | 'quantity' => 10, 88 | 'amount' => -15000 89 | ] 90 | ]); 91 | } 92 | 93 | public function testExceptionOnEmptyCart() 94 | { 95 | $this->expectException(CartEmptyException::class); 96 | 97 | $cart = $this->onepay->createCart([ 98 | 'items' => [] 99 | ]); 100 | } 101 | } -------------------------------------------------------------------------------- /src/Transactions/AbstractTransaction.php: -------------------------------------------------------------------------------- 1 | $method(); 50 | } 51 | 52 | // Do any logic before getting the result 53 | if (method_exists($this, $method = 'performPreLogic') && is_callable([$this, $method])) { 54 | $this->$method(); 55 | } 56 | 57 | if ($this->response = $this->service->commit($this)) { 58 | $this->performed = true; 59 | } 60 | 61 | return $this->response; 62 | } 63 | 64 | /** 65 | * Set default attributes for the Item 66 | * 67 | * @param array $defaults 68 | */ 69 | public function setDefaults(array $defaults) 70 | { 71 | $this->attributes = array_merge($defaults, $this->attributes ?? []); 72 | } 73 | 74 | /** 75 | * Set the Transaction type 76 | * 77 | * @param string $type 78 | */ 79 | public function setType(string $type) 80 | { 81 | $this->type = $type; 82 | } 83 | 84 | /** 85 | * Return the Transaction type 86 | * 87 | * @return string 88 | */ 89 | public function getType() 90 | { 91 | return $this->type; 92 | } 93 | 94 | /** 95 | * Sets the Service to be used for this Transaction 96 | * 97 | * @param ServiceInterface $service 98 | */ 99 | public function setService(ServiceInterface $service) 100 | { 101 | $this->service = $service; 102 | } 103 | 104 | /** 105 | * Returns the Service used by this Transaction 106 | * 107 | * @return ServiceInterface 108 | */ 109 | public function getService() 110 | { 111 | return $this->service; 112 | } 113 | 114 | /** 115 | * Commits the transaction to Transbank and return a AbstractResult 116 | * 117 | * @return \DarkGhostHunter\TransbankApi\Responses\AbstractResponse 118 | */ 119 | public function commit() 120 | { 121 | return $this->performed ? $this->response : $this->performCommit(); 122 | } 123 | 124 | /** 125 | * Forcefully commits the transaction to Transbank 126 | * 127 | * @return \DarkGhostHunter\TransbankApi\Responses\AbstractResponse 128 | */ 129 | public function forceCommit() 130 | { 131 | return $this->performCommit(); 132 | } 133 | } -------------------------------------------------------------------------------- /tests/Unit/Clients/Webpay/PlusCaptureTest.php: -------------------------------------------------------------------------------- 1 | client = new PlusCapture(true, new Fluid(['privateKey' => 'foo', 'publicCert' => 'bar'])); 32 | 33 | $this->client->boot(); 34 | 35 | $this->mockConnector = \Mockery::instanceMock(SoapImplementation::class); 36 | 37 | $this->mockValidator = \Mockery::instanceMock('overload:' . Validation::class) 38 | ->makePartial(); 39 | 40 | $this->client->setConnector($this->mockConnector); 41 | } 42 | 43 | public function testCapture() 44 | { 45 | $this->mockValidator->expects('isValid')->andReturnTrue(); 46 | 47 | $transaction = new WebpayTransaction([ 48 | 'buyOrder' => 'baz', 49 | 'amount' => 'qux', 50 | ]); 51 | 52 | $this->mockConnector 53 | ->expects('capture') 54 | ->with(\Mockery::type('array')) 55 | ->andReturn( 56 | (object)['return' => ['foo' => 'bar']] 57 | ); 58 | 59 | $this->mockConnector 60 | ->expects('__getLastResponse') 61 | ->andReturn('foo'); 62 | 63 | $response = $this->client->capture($transaction); 64 | 65 | $this->assertEquals('bar', $response['foo']); 66 | } 67 | 68 | public function testExceptionOnCapture() 69 | { 70 | $this->expectException(ErrorResponseException::class); 71 | 72 | $this->mockValidator->expects('isValid')->andReturnTrue(); 73 | 74 | $transaction = new WebpayTransaction([ 75 | 'buyOrder' => 'baz', 76 | 'amount' => 'qux', 77 | ]); 78 | 79 | $this->mockConnector 80 | ->expects('capture') 81 | ->with(\Mockery::type('array')) 82 | ->andThrow(\Exception::class); 83 | 84 | $this->mockConnector 85 | ->expects('__getLastResponse') 86 | ->andReturn('foo'); 87 | 88 | $this->client->capture($transaction); 89 | } 90 | 91 | public function testExceptionOnCaptureNotValid() 92 | { 93 | $this->expectException(InvalidSignatureException::class); 94 | 95 | $this->mockValidator->expects('isValid')->andReturnFalse(); 96 | 97 | $transaction = new WebpayTransaction([ 98 | 'buyOrder' => 'baz', 99 | 'amount' => 'qux', 100 | ]); 101 | 102 | $this->mockConnector 103 | ->expects('capture') 104 | ->with(\Mockery::type('array')) 105 | ->andReturn( 106 | (object)['return' => ['foo' => 'bar']] 107 | ); 108 | 109 | $this->mockConnector 110 | ->expects('__getLastResponse') 111 | ->andReturn('foo'); 112 | 113 | $this->client->capture($transaction); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /tests/Unit/Clients/Webpay/PlusNullifyTest.php: -------------------------------------------------------------------------------- 1 | client = new PlusNullify(true, new Fluid(['privateKey' => 'foo', 'publicCert' => 'bar'])); 32 | 33 | $this->client->boot(); 34 | 35 | $this->mockConnector = \Mockery::instanceMock(SoapImplementation::class); 36 | 37 | $this->mockValidator = \Mockery::instanceMock('overload:' . Validation::class) 38 | ->makePartial(); 39 | 40 | $this->client->setConnector($this->mockConnector); 41 | } 42 | 43 | public function testNullify() 44 | { 45 | $this->mockValidator->expects('isValid')->andReturnTrue(); 46 | 47 | $transaction = new WebpayTransaction([ 48 | 'buyOrder' => 'baz', 49 | 'amount' => 'qux', 50 | ]); 51 | 52 | $this->mockConnector 53 | ->expects('nullify') 54 | ->with(\Mockery::type('array')) 55 | ->andReturn( 56 | (object)['return' => ['foo' => 'bar']] 57 | ); 58 | 59 | $this->mockConnector 60 | ->expects('__getLastResponse') 61 | ->andReturn('foo'); 62 | 63 | $response = $this->client->nullify($transaction); 64 | 65 | $this->assertEquals('bar', $response['foo']); 66 | } 67 | 68 | public function testExceptionNullify() 69 | { 70 | $this->expectException(ErrorResponseException::class); 71 | 72 | $this->mockValidator->expects('isValid')->andReturnTrue(); 73 | 74 | $transaction = new WebpayTransaction([ 75 | 'buyOrder' => 'baz', 76 | 'amount' => 'qux', 77 | ]); 78 | 79 | $this->mockConnector 80 | ->expects('nullify') 81 | ->with(\Mockery::type('array')) 82 | ->andThrow(\Exception::class); 83 | 84 | $this->mockConnector 85 | ->expects('__getLastResponse') 86 | ->andReturn('foo'); 87 | 88 | $response = $this->client->nullify($transaction); 89 | 90 | $this->assertEquals('bar', $response['foo']); 91 | } 92 | 93 | public function testExceptionNullifyInvalid() 94 | { 95 | $this->expectException(InvalidSignatureException::class); 96 | 97 | $this->mockValidator->expects('isValid')->andReturnFalse(); 98 | 99 | $transaction = new WebpayTransaction([ 100 | 'buyOrder' => 'baz', 101 | 'amount' => 'qux', 102 | ]); 103 | 104 | $this->mockConnector 105 | ->expects('nullify') 106 | ->with(\Mockery::type('array')) 107 | ->andReturn( 108 | (object)['return' => ['foo' => 'bar']] 109 | ); 110 | 111 | $this->mockConnector 112 | ->expects('__getLastResponse') 113 | ->andReturn('foo'); 114 | 115 | $this->client->nullify($transaction); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tests/Unit/TransactionFactories/OnepayTransactionFactoryTest.php: -------------------------------------------------------------------------------- 1 | mockTransbank = \Mockery::mock(Transbank::class); 30 | $this->mockTransbank->shouldReceive('getDefaults')->once() 31 | ->andReturn(['foo' => 'bar']); 32 | $this->mockTransbank->shouldReceive('getCredentials')->once() 33 | ->with('onepay') 34 | ->andReturn(new Fluid(['foo' => 'bar'])); 35 | $this->mockTransbank->shouldReceive('isProduction')->once() 36 | ->andReturnTrue(); 37 | $this->mockTransbank->shouldReceive('getEnvironment') 38 | ->andReturn('production'); 39 | 40 | $this->mockAdapter = \Mockery::mock(OnepayAdapter::class); 41 | 42 | $this->onepay = new Onepay($this->mockTransbank, new NullLogger()); 43 | $this->onepay->setAdapter($this->mockAdapter); 44 | } 45 | 46 | public function testCreateNullify() 47 | { 48 | $this->mockAdapter->shouldReceive('setCredentials')->once() 49 | ->andReturn(['foo' => 'bar']); 50 | $this->mockAdapter->shouldReceive('commit')->once() 51 | ->andReturnUsing(function ($transaction) { 52 | $this->assertInstanceOf(OnepayNullifyTransaction::class, $transaction); 53 | return $transaction->toArray(); 54 | }); 55 | 56 | $response = $this->onepay->createNullify([ 57 | 'foo' => 'bar', 58 | 'amount' => 1, 59 | 'quantity' => 1, 60 | ]); 61 | 62 | $this->assertInstanceOf(OnepayResponse::class, $response); 63 | $this->assertEquals('bar', $response->foo); 64 | $this->assertEquals(1, $response->amount); 65 | $this->assertEquals(1, $response->quantity); 66 | } 67 | 68 | public function testMakeCart() 69 | { 70 | $cart = $this->onepay->makeCart([ 71 | 'foo' => 'bar' 72 | ]); 73 | 74 | $this->assertInstanceOf(OnepayTransaction::class, $cart); 75 | $this->assertEquals('bar', $cart->foo); 76 | } 77 | 78 | public function testCreateCart() 79 | { 80 | $this->mockAdapter->shouldReceive('setCredentials')->once() 81 | ->andReturn(['foo' => 'bar']); 82 | $this->mockAdapter->shouldReceive('commit')->once() 83 | ->andReturnUsing(function ($transaction) { 84 | $this->assertInstanceOf(OnepayTransaction::class, $transaction); 85 | return $transaction->items[0]->toArray(); 86 | }); 87 | 88 | $response = $this->onepay->createCart([ 89 | 'items' => [ 90 | 'foo' => 'bar', 91 | 'amount' => 1, 92 | 'quantity' => 1, 93 | ] 94 | ]); 95 | 96 | $this->assertInstanceOf(OnepayResponse::class, $response); 97 | $this->assertEquals('bar', $response->foo); 98 | $this->assertEquals(1, $response->amount); 99 | $this->assertEquals(1, $response->quantity); 100 | } 101 | 102 | public function testMakeNullify() 103 | { 104 | $nullify = $this->onepay->makeNullify([ 105 | 'foo' => 'bar' 106 | ]); 107 | 108 | $this->assertInstanceOf(OnepayNullifyTransaction::class, $nullify); 109 | $this->assertEquals('bar', $nullify->foo); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Versión 4.0 Final 2 | 3 | Como leen, esta será la última versión de Transbank API. El nuevo SDK oficial de Transbank usa HTTPS en vez de SOAP (puaj!), así que este SDK ya no es necesario. 4 | 5 | # Ve y usa el [SDK Oficial de Transbank](https://github.com/TransbankDevelopers/transbank-sdk-php) 6 | 7 | ![rawpixel - Unsplash (UL) #SEDqvdbkDQw](https://images.unsplash.com/photo-1535603383947-c1ee27a4906f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1280&h=400&q=80) 8 | 9 | [![Latest Stable Version](https://poser.pugx.org/darkghosthunter/transbank-api/v/stable)](https://packagist.org/packages/darkghosthunter/transbank-api) [![License](https://poser.pugx.org/darkghosthunter/transbank-api/license)](https://packagist.org/packages/darkghosthunter/transbank-api) 10 | ![](https://img.shields.io/packagist/php-v/darkghosthunter/transbank-api.svg) [![PHP Composer](https://github.com/DarkGhostHunter/TransbankApi/workflows/PHP%20Composer/badge.svg)](https://github.com/DarkGhostHunter/TransbankApi/actions) [![Coverage Status](https://coveralls.io/repos/github/DarkGhostHunter/TransbankApi/badge.svg?branch=master)](https://coveralls.io/github/DarkGhostHunter/TransbankApi?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/4a6d823102cea362adfd/maintainability)](https://codeclimate.com/github/DarkGhostHunter/TransbankApi/maintainability) 11 | 12 | 13 | # Transbank API 14 | 15 | `TransbankApi` es un reemplazo al [Transbank SDK](https://github.com/TransbankDevelopers/transbank-sdk-php) con la finalidad de mejorar la experiencia de integración y uso. 16 | 17 | > Esta versión es incompatible con PHP 5. Para usar este código con PHP 5, usa el packete oficial de [Transbank SDK](https://github.com/TransbankDevelopers/transbank-sdk-php). 18 | 19 | ## Requisitos: 20 | 21 | - PHP 7.4, o PHP 8.0 22 | - Composer 23 | 24 | ## Dependencias 25 | 26 | Este paquete usa [Guzzle HTTP 7.0](http://docs.guzzlephp.org/en/stable/) y la [implementación de SOAP de Luis Urrutia](https://github.com/LuisUrrutia/TransbankSoap). 27 | 28 | A su vez, este paquete necesita las siguientes extensiones de PHP habilitadas: 29 | 30 | * ext-curl 31 | * ext-json 32 | * ext-mbstring 33 | * ext-soap 34 | * ext-dom 35 | 36 | Instalarlas dependerá de tu sistema: en algunos casos sólo necesitarás habilitarlas en tu `php.ini`; en otros, descargarlas usando tu gestor de packetes (como `apt-get` o `apk`) o compilarlas manualmente. 37 | 38 | ### Logger 39 | 40 | Esta librería es compatible con cualquier [logger PSR-3](https://www.php-fig.org/psr/psr-3/). Si quieres que tu proyecto escriba información sobre las transacciones, puedes usar [Monolog](https://github.com/Seldaek/monolog/) o cualquier otro que siga el estándar. 41 | 42 | # Instalación 43 | 44 | Hay tres formas para instalar el paquete: usando Composer, sin composer, y todo de forma (muy) manual. 45 | 46 | ### Instalar con Composer 47 | 48 | Para usar el SDK en tu proyecto usa Composer: 49 | 50 | ```bash 51 | composer require darkghosthunter/transbank-api 52 | ``` 53 | 54 | ## Documentación 55 | 56 | La documentación de este paquete está [en la Wiki](https://github.com/DarkGhostHunter/TransbankApi/wiki). 57 | 58 | Sin embargo, la idea de este paquete es que puedas realizar la mayoría de tus transacciones usando sintaxis expresiva: 59 | 60 | La información sobre las variables que necesitas para realizar cada transacción está en [Transbank Developers](https://www.transbankdevelopers.cl). Este paquete no modifica el nombre de las variables. 61 | 62 | ## Ejemplos 63 | 64 | Este paquete incluye una pequeña sección de ejemplos que te permitirán probar (y ver en acción) cómo funciona la interacción con los distintos servicios Transbank en modo `integration`. 65 | 66 | Sólo dirígete al [directorio `examples`](examples) y sigue las instrucciones. 67 | 68 | ## Información para contribuir y desarrollar este Wrapper 69 | 70 | Tirar la talla en buen chileno en los PR. Si usas otro idioma, serás víctima de bullying. 71 | 72 | # Licencia 73 | 74 | Este paquete está licenciado bajo la [Licencia MIT](LICENCIA) [(En inglés)](LICENSE). 75 | 76 | `Redcompra`, `Webpay`, `Onepay`, `Patpass` y `tbk` son marcas registradas de [Transbank S.A.](https://www.transbank.cl/) 77 | 78 | Este paquete no está aprobado, apoyado ni avalado por Transbank S.A. ni ninguna persona natural o jurídica vinculada directa o indirectamente a Transbank S.A. 79 | -------------------------------------------------------------------------------- /src/Clients/Webpay/PlusNormal.php: -------------------------------------------------------------------------------- 1 | $this->credentials->commerceCode, 37 | 'buyOrder' => $transaction->buyOrder, 38 | 'amount' => $transaction->amount, 39 | ] 40 | ]; 41 | // Otherwise, we will change the transaction type to Mall and... 42 | } else { 43 | $commit['wSTransactionType'] = 'TR_MALL_WS'; 44 | $commit['commerceId'] = $this->credentials->commerceCode; 45 | } 46 | 47 | // ..for each item (even if its one), transform it as something 48 | // Soap Connector can digest. 49 | foreach ($commit['transactionDetails'] as &$item) { 50 | $item = (object)[ 51 | 'commerceCode' => $item['commerceCode'], 52 | 'buyOrder' => $item['buyOrder'], 53 | 'amount' => $item['amount'], 54 | ]; 55 | } 56 | 57 | return (object)$commit; 58 | } 59 | 60 | /** 61 | * Commits a Normal or Mall Transaction into Webpay 62 | * 63 | * @param WebpayTransaction $transaction 64 | * @return array 65 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\Webpay\ErrorResponseException 66 | * @throws InvalidSignatureException 67 | */ 68 | public function commit(WebpayTransaction $transaction) 69 | { 70 | // Create a normal transaction using the Fluid Helper 71 | $commit = $this->makeCommit([ 72 | 'wSTransactionType' => 'TR_NORMAL_WS', 73 | 'sessionId' => $transaction->sessionId, 74 | 'buyOrder' => $transaction->buyOrder, 75 | 'returnURL' => $transaction->returnUrl, 76 | 'finalURL' => $transaction->finalUrl, 77 | 'transactionDetails' => $transaction->items, 78 | ], $transaction); 79 | 80 | try { 81 | // Now that we have the transaction completed, commit it 82 | $response = $this->performCommit($commit); 83 | } catch (Exception $e) { 84 | throw new ErrorResponseException($e->getMessage(), $e->getCode(), $e); 85 | } 86 | 87 | if ($this->validate()) { 88 | return $response; 89 | } 90 | 91 | throw new InvalidSignatureException(); 92 | } 93 | 94 | /** 95 | * Obtains the Transaction results from Webpay Soap 96 | * 97 | * @param string $transaction 98 | * @return array 99 | * @throws InvalidSignatureException 100 | */ 101 | public function retrieveAndConfirm($transaction) 102 | { 103 | // Retrieve Transaction result 104 | $response = $this->retrieve($transaction); 105 | 106 | // If Validation passes and the Transaction is Confirmed... 107 | if ($this->validate() && $this->confirm($transaction)) { 108 | // Extract the results from the response and return it 109 | return $response; 110 | } 111 | 112 | throw new InvalidSignatureException(); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/Onepay.php: -------------------------------------------------------------------------------- 1 | bootAdapter(); 57 | $this->bootTransactionFactory(); 58 | } 59 | 60 | /** 61 | * Instantiates (and/or boots) the Adapter for the Service 62 | * 63 | * @return void 64 | */ 65 | public function bootAdapter() 66 | { 67 | $this->adapter = new OnepayAdapter(); 68 | } 69 | 70 | /** 71 | * Instantiates (and/or boots) the Transaction Factory for the Service 72 | * 73 | * @return void 74 | */ 75 | public function bootTransactionFactory() 76 | { 77 | $this->transactionFactory = new OnepayTransactionFactory($this, $this->defaults); 78 | } 79 | 80 | /* 81 | |-------------------------------------------------------------------------- 82 | | Credentials 83 | |-------------------------------------------------------------------------- 84 | */ 85 | 86 | /** 87 | * Get the Service Credentials for the Production Environment 88 | * 89 | * @return array 90 | */ 91 | protected function getProductionCredentials() 92 | { 93 | return include __DIR__ . '/' . 94 | trim(self::CREDENTIALS_DIR, '/') . '/' . 95 | trim(self::PRODUCTION_KEYS, '/'); 96 | } 97 | 98 | /** 99 | * Get the Service Credentials for the Integration Environment 100 | * 101 | * @param string $type 102 | * @return array 103 | */ 104 | protected function getIntegrationCredentials(string $type = null) 105 | { 106 | return include __DIR__ . '/' . 107 | trim(self::CREDENTIALS_DIR, '/') . '/' . 108 | trim(self::INTEGRATION_KEYS, '/'); 109 | } 110 | 111 | /* 112 | |-------------------------------------------------------------------------- 113 | | Operations 114 | |-------------------------------------------------------------------------- 115 | */ 116 | 117 | /** 118 | * Gets and Acknowledges a Transaction in Transbank 119 | * 120 | * @param $transaction 121 | * @param $options 122 | * @return Contracts\ResponseInterface 123 | */ 124 | public function getTransaction($transaction, $options = null) 125 | { 126 | // Add the `issuedAt` timestamp for getting the transaction 127 | return parent::getTransaction($transaction + ['issuedAt' => time()], 'onepay.cart'); 128 | } 129 | 130 | /* 131 | |-------------------------------------------------------------------------- 132 | | Parsers 133 | |-------------------------------------------------------------------------- 134 | */ 135 | 136 | /** 137 | * Transform the adapter raw answer of a transaction commitment to a 138 | * more friendly Onepay Response 139 | * 140 | * @param array $result 141 | * @param mixed $options 142 | * @return Contracts\ResponseInterface 143 | */ 144 | protected function parseResponse(array $result, $options = null) 145 | { 146 | $response = new OnepayResponse($result); 147 | 148 | // Set the type of the Transaction where this response belongs 149 | $response->setType($options); 150 | 151 | // Set the status of the Response 152 | $response->dynamicallySetSuccessStatus(); 153 | 154 | return $response; 155 | } 156 | } -------------------------------------------------------------------------------- /src/Responses/AbstractResponse.php: -------------------------------------------------------------------------------- 1 | tokenName; 114 | } 115 | 116 | /** 117 | * Sets the Token Name for redirection 118 | * 119 | * @param string $tokenName 120 | */ 121 | public function setTokenName(string $tokenName) 122 | { 123 | $this->tokenName = $tokenName; 124 | } 125 | 126 | /** 127 | * Gets the Transaction Type for the Response (if available) 128 | * 129 | * @return string 130 | */ 131 | public function getType() 132 | { 133 | return $this->type; 134 | } 135 | 136 | /** 137 | * Sets the Transaction Type for the Response (if available) 138 | * 139 | * @param string $type 140 | */ 141 | public function setType(string $type) 142 | { 143 | $this->type = $type; 144 | } 145 | 146 | /* 147 | |-------------------------------------------------------------------------- 148 | | Success indicator 149 | |-------------------------------------------------------------------------- 150 | */ 151 | 152 | /** 153 | * Return if the Response is a success 154 | * 155 | * @return bool 156 | */ 157 | public function isSuccess() 158 | { 159 | return $this->isSuccess; 160 | } 161 | 162 | /** 163 | * Returns if the Response was a failure 164 | * 165 | * @return bool 166 | */ 167 | public function isFailed() 168 | { 169 | return !$this->isSuccess(); 170 | } 171 | 172 | /* 173 | |-------------------------------------------------------------------------- 174 | | Error Handling 175 | |-------------------------------------------------------------------------- 176 | */ 177 | 178 | /** 179 | * Returns the loaded array of Error translations (or loads it) 180 | * 181 | * @return array|bool|string 182 | */ 183 | protected static function getLoadedErrorList() 184 | { 185 | return self::$translationList 186 | ? self::$translationList 187 | : self::$translationList = include_once(self::TRANSLATION_LIST_FILE); 188 | } 189 | 190 | /** 191 | * Returns the Error Code if the transaction was a failure 192 | * 193 | * @return string 194 | */ 195 | public function getErrorCode() 196 | { 197 | return $this->errorCode; 198 | } 199 | 200 | /** 201 | * Returns the error as an understandable text string 202 | * 203 | * @return mixed 204 | */ 205 | public function getErrorForHumans() 206 | { 207 | return self::getLoadedErrorList()[$this->listKey][$this->errorCode] ?? null; 208 | } 209 | 210 | } -------------------------------------------------------------------------------- /src/ResponseFactories/WebpayResponseFactory.php: -------------------------------------------------------------------------------- 1 | service->getTransaction($transaction, 'plus.normal'); 23 | } 24 | 25 | /** 26 | * Retrieves a Webpay Plus Normal Transaction 27 | * 28 | * @param string $transaction 29 | * @return \DarkGhostHunter\TransbankApi\Responses\WebpayPlusResponse 30 | */ 31 | public function retrieveNormal(string $transaction) 32 | { 33 | return $this->service->retrieveTransaction($transaction, 'plus.normal'); 34 | } 35 | 36 | /** 37 | * Confirms a Webpay Plus Normal Transaction 38 | * 39 | * @param string $transaction 40 | * @return \DarkGhostHunter\TransbankApi\Responses\WebpayPlusResponse 41 | */ 42 | public function confirmNormal(string $transaction) 43 | { 44 | return $this->service->confirmTransaction($transaction, 'plus.normal'); 45 | } 46 | 47 | /* 48 | |-------------------------------------------------------------------------- 49 | | Webpay Plus Mall Normal 50 | |-------------------------------------------------------------------------- 51 | */ 52 | 53 | /** 54 | * Retrieves and Confirms a Webpay Plus Mall Normal Transaction 55 | * 56 | * @param string $transaction 57 | * @return \DarkGhostHunter\TransbankApi\Contracts\ResponseInterface|\DarkGhostHunter\TransbankApi\Responses\WebpayPlusMallResponse 58 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\Webpay\TransactionTypeNullException 59 | */ 60 | public function getMallNormal(string $transaction) 61 | { 62 | return $this->service->getTransaction($transaction, 'plus.mall.normal'); 63 | } 64 | 65 | /** 66 | * Retrieves a Webpay Plus Mall Normal Transaction 67 | * 68 | * @param string $transaction 69 | * @return \DarkGhostHunter\TransbankApi\Contracts\ResponseInterface|\DarkGhostHunter\TransbankApi\Responses\WebpayPlusMallResponse 70 | */ 71 | public function retrieveMallNormal(string $transaction) 72 | { 73 | return $this->service->retrieveTransaction($transaction, 'plus.mall.normal'); 74 | } 75 | 76 | /** 77 | * Confirms a Webpay Plus Mall Normal Transaction 78 | * 79 | * @param string $transaction 80 | * @return \DarkGhostHunter\TransbankApi\Responses\WebpayPlusResponse 81 | */ 82 | public function confirmMallNormal(string $transaction) 83 | { 84 | return $this->service->confirmTransaction($transaction, 'plus.mall.normal'); 85 | } 86 | 87 | /* 88 | |-------------------------------------------------------------------------- 89 | | Webpay Plus Deferred 90 | |-------------------------------------------------------------------------- 91 | */ 92 | 93 | /** 94 | * Retrieves and Confirms a Webpay Plus Deferred Transaction 95 | * 96 | * @param string $transaction 97 | * @return \DarkGhostHunter\TransbankApi\Responses\WebpayPlusMallResponse|\DarkGhostHunter\TransbankApi\Responses\WebpayPlusResponse 98 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\Webpay\TransactionTypeNullException 99 | */ 100 | public function getDefer(string $transaction) 101 | { 102 | return $this->service->getTransaction($transaction, 'plus.defer'); 103 | } 104 | 105 | /** 106 | * Retrieves a Webpay Plus Deferred Transaction 107 | * 108 | * @param string $transaction 109 | * @return \DarkGhostHunter\TransbankApi\Responses\WebpayPlusMallResponse|\DarkGhostHunter\TransbankApi\Responses\WebpayPlusResponse 110 | */ 111 | public function retrieveDefer(string $transaction) 112 | { 113 | return $this->service->retrieveTransaction($transaction, 'plus.defer'); 114 | } 115 | 116 | /** 117 | * Confirms a Webpay Plus Deferred Transaction 118 | * 119 | * @param string $transaction 120 | * @return \DarkGhostHunter\TransbankApi\Responses\WebpayPlusResponse 121 | */ 122 | public function confirmDefer(string $transaction) 123 | { 124 | return $this->service->confirmTransaction($transaction, 'plus.defer'); 125 | } 126 | 127 | /* 128 | |-------------------------------------------------------------------------- 129 | | Webpay Oneclick Registration 130 | |-------------------------------------------------------------------------- 131 | */ 132 | 133 | /** 134 | * Confirms the Webpay Oneclick Registration 135 | * 136 | * @param string $transaction 137 | * @return \DarkGhostHunter\TransbankApi\Responses\WebpayPlusResponse 138 | */ 139 | public function getRegistration(string $transaction) 140 | { 141 | return $this->service->confirmTransaction($transaction, 'oneclick.confirm'); 142 | } 143 | 144 | /** 145 | * Alias for getRegistration() 146 | * 147 | * @param string $transaction 148 | * @return \DarkGhostHunter\TransbankApi\Responses\WebpayPlusResponse 149 | */ 150 | public function confirmRegistration(string $transaction) 151 | { 152 | return $this->getRegistration($transaction); 153 | } 154 | 155 | } -------------------------------------------------------------------------------- /src/Clients/Webpay/WebpayClient.php: -------------------------------------------------------------------------------- 1 | [ 20 | 'integration' => 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl', 21 | 'production' => 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl', 22 | ], 23 | 'commerce' => [ 24 | 'integration' => 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl', 25 | 'production' => 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl', 26 | ], 27 | 'complete' => [ 28 | 'integration' => 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSCompleteWebpayService?wsdl', 29 | 'production' => 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSCompleteWebpayService?wsdl', 30 | ], 31 | 'oneclick' => [ 32 | 'integration' => 'https://webpay3gint.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl', 33 | 'production' => 'https://webpay3g.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl', 34 | ], 35 | ]; 36 | 37 | /** 38 | * Endpoint type to use 39 | * 40 | * @var string 41 | */ 42 | protected $endpointType; 43 | 44 | /** 45 | * Class map for SOAP 46 | * 47 | * @var array 48 | */ 49 | protected $classMap; 50 | 51 | /** 52 | * Soap Connector 53 | * 54 | * @var SoapImplementation|SoapClient 55 | */ 56 | protected $connector; 57 | 58 | /* 59 | |-------------------------------------------------------------------------- 60 | | Getters and Setters 61 | |-------------------------------------------------------------------------- 62 | */ 63 | 64 | /** 65 | * Get the Soap Connector 66 | * 67 | * @return SoapImplementation 68 | */ 69 | public function getConnector() 70 | { 71 | return $this->connector; 72 | } 73 | 74 | /** 75 | * Set the Soap Connector 76 | * 77 | * @param SoapImplementation|SoapClient $connector 78 | */ 79 | public function setConnector(SoapClient $connector) 80 | { 81 | $this->connector = $connector; 82 | } 83 | 84 | /** 85 | * Get the Endpoint Type 86 | * 87 | * @return string 88 | */ 89 | public function getEndpointType() 90 | { 91 | return $this->endpointType; 92 | } 93 | 94 | /** 95 | * Set the Endpoint Type 96 | * 97 | * @param string $endpointType 98 | */ 99 | public function setEndpointType(string $endpointType) 100 | { 101 | $this->endpointType = $endpointType; 102 | } 103 | 104 | /* 105 | |-------------------------------------------------------------------------- 106 | | Initialization 107 | |-------------------------------------------------------------------------- 108 | */ 109 | 110 | /** 111 | * Boot the connector 112 | * 113 | * @return void 114 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\TransbankUnavailableException 115 | */ 116 | public function boot() 117 | { 118 | $this->bootEndpoint(); 119 | 120 | $this->bootClassMap(); 121 | 122 | $this->bootSoapClient(); 123 | } 124 | 125 | /** 126 | * Creates a new instance of the Soap Client using the Configuration as base 127 | * 128 | * @return void 129 | * @throws \DarkGhostHunter\TransbankApi\Exceptions\TransbankUnavailableException 130 | */ 131 | protected function bootSoapClient() 132 | { 133 | try { 134 | $this->connector = new SoapImplementation( 135 | $this->endpoint, 136 | $this->credentials->privateKey, 137 | $this->credentials->publicCert, 138 | [ 139 | 'classmap' => $this->classMap, 140 | 'trace' => true, 141 | 'exceptions' => true 142 | ] 143 | ); 144 | } catch (SoapFault $exception) { 145 | throw new TransbankUnavailableException(null, null, $exception); 146 | } 147 | } 148 | 149 | /** 150 | * Initializes the Class Map to give to the Soap Client 151 | * 152 | * @return void 153 | */ 154 | protected function bootClassMap() 155 | { 156 | $this->classMap = include __DIR__ . '/classmaps.php'; 157 | } 158 | 159 | /** 160 | * Sets the Endpoint to use depending on the environment type 161 | * 162 | * @return void 163 | */ 164 | protected function bootEndpoint() 165 | { 166 | $this->endpoint = self::$endpoints[$this->endpointType][$this->isProduction ? 'production' : 'integration']; 167 | } 168 | 169 | /* 170 | |-------------------------------------------------------------------------- 171 | | Common functions for all Transactions 172 | |-------------------------------------------------------------------------- 173 | */ 174 | 175 | /** 176 | * Validates the last response from the SoapClient 177 | * 178 | * @return bool 179 | */ 180 | protected function validate() 181 | { 182 | return (new Validation( 183 | $this->connector->__getLastResponse(), 184 | $this->credentials->webpayCert 185 | ))->isValid(); 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/Transactions/Concerns/HasItems.php: -------------------------------------------------------------------------------- 1 | 1 && !Helpers::isNumericArray($items)) { 28 | $items = [$items]; 29 | } 30 | 31 | $this->addItems($items); 32 | } 33 | 34 | /** 35 | * Parse the Item we are getting 36 | * 37 | * @param $item 38 | * @return null 39 | */ 40 | protected function parseItem($item) 41 | { 42 | // First, let's try to decode this Item 43 | if (is_string($item) && $array = json_decode($item, true)) { 44 | $item = $array; 45 | } 46 | 47 | // If it was decoded, then return the Item 48 | if (is_array($item)) { 49 | return new Item(array_merge($item, $this->itemDefaults ?? [])); 50 | } 51 | 52 | // We did nothing, so we return nothing 53 | return null; 54 | } 55 | 56 | /** 57 | * Add an Item, or multiple Items 58 | * 59 | * @param array $items 60 | */ 61 | public function addItem(...$items) 62 | { 63 | foreach ($items as $item) { 64 | // Add the Item only if we can parse it 65 | if ($item = $this->parseItem($item)) { 66 | $this->items[] = $item; 67 | } 68 | } 69 | } 70 | 71 | /** 72 | * Add multiple items. 73 | * 74 | * @param array $items 75 | */ 76 | public function addItems(array $items) 77 | { 78 | $this->addItem(...$items); 79 | } 80 | 81 | /** 82 | * Return all the Items in the OnepayTransaction 83 | * 84 | * @return array 85 | */ 86 | public function getItems() 87 | { 88 | return $this->items; 89 | } 90 | 91 | /** 92 | * Dynamically gets the Items 93 | * 94 | * @return array 95 | */ 96 | public function getItemsAttribute() 97 | { 98 | return $this->getItems(); 99 | } 100 | 101 | /** 102 | * Gets a particular Item from the OnepayTransaction by its Key 103 | * 104 | * @param int $key 105 | * @return mixed|null 106 | */ 107 | public function getItem(int $key) 108 | { 109 | return $this->items[$key] ?? null; 110 | } 111 | 112 | /** 113 | * Get an Item by its exact description 114 | * 115 | * @param string $description 116 | * @return mixed|null 117 | */ 118 | public function getItemByDescription(string $description) 119 | { 120 | foreach ($this->items as $item) { 121 | if ($item->description === $description) { 122 | return $item; 123 | } 124 | } 125 | return null; 126 | } 127 | 128 | /** 129 | * Get an Item Key by its Description 130 | * 131 | * @param string $description 132 | * @return int|null|string 133 | */ 134 | public function getItemKeyByDescription(string $description) 135 | { 136 | foreach ($this->items as $key => $item) { 137 | if ($item->description === $description) { 138 | return $key; 139 | } 140 | } 141 | return null; 142 | } 143 | 144 | /** 145 | * Deletes an Item by its Key 146 | * 147 | * @param int $key 148 | * @return bool 149 | */ 150 | public function deleteItem(int $key) 151 | { 152 | if (isset($this->items[$key])) { 153 | unset($this->items[$key]); 154 | return true; 155 | } 156 | return false; 157 | } 158 | 159 | /** 160 | * Deletes an Item by its Description 161 | * 162 | * @param string $description 163 | * @return bool 164 | */ 165 | public function deleteItemByDescription(string $description) 166 | { 167 | if ($key = $this->getItemKeyByDescription($description)) { 168 | return $this->deleteItem($key); 169 | } 170 | return false; 171 | } 172 | 173 | /** 174 | * Updates an Item attributes, replacing or adding them, and return the result 175 | * 176 | * @param int $key 177 | * @param array $attributes 178 | * @return object|bool 179 | */ 180 | public function updateItem(int $key, array $attributes) 181 | { 182 | if (isset($this->items[$key])) { 183 | 184 | $this->items[$key]->setAttributes( 185 | array_merge($this->items[$key]->getAttributes(), $attributes) 186 | ); 187 | 188 | return $this->items[$key]; 189 | } 190 | return false; 191 | } 192 | 193 | /** 194 | * Replaces completely an Item with another 195 | * 196 | * @param int $key 197 | * @param $item 198 | * @return bool 199 | */ 200 | public function replaceItem(int $key, $item) 201 | { 202 | if (isset($this->items[$key])) { 203 | return !!($this->items[$key] = $this->parseItem($item)); 204 | } 205 | return false; 206 | } 207 | 208 | /** 209 | * Count all Items in the OnepayTransaction 210 | * 211 | * @return int 212 | */ 213 | public function countItems() 214 | { 215 | return count($this->items); 216 | } 217 | 218 | 219 | /** 220 | * Clears the Items array 221 | * 222 | * @return void 223 | */ 224 | public function clearItems() 225 | { 226 | $this->items = []; 227 | } 228 | 229 | /** 230 | * Reindex the Items array 231 | * 232 | * @return void 233 | */ 234 | public function reindexItems() 235 | { 236 | $this->items = array_values($this->items); 237 | } 238 | } -------------------------------------------------------------------------------- /src/Responses/WebpayPlusMallResponse.php: -------------------------------------------------------------------------------- 1 | detailOutput) { 30 | $this->detailOutput = is_array($this->detailOutput) 31 | ? $this->detailOutput 32 | : [$this->detailOutput]; 33 | } 34 | 35 | } 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Status 40 | |-------------------------------------------------------------------------- 41 | */ 42 | 43 | /** 44 | * Detect if the Result was successful or not 45 | * 46 | * @return void 47 | */ 48 | public function dynamicallySetSuccessStatus() 49 | { 50 | if ($this->token) { 51 | $this->isSuccess = true; 52 | return; 53 | } 54 | 55 | if ($this->detailOutput) { 56 | $this->isSuccess = $this->allItemsAreOk($this->detailOutput); 57 | } 58 | } 59 | 60 | /** 61 | * Detect if all the items returned in the response are successful 62 | * 63 | * @param array|null $items 64 | * @return bool 65 | */ 66 | protected function allItemsAreOk(array $items) 67 | { 68 | foreach ($items as $item) { 69 | if ($item->responseCode !== 0) { 70 | return false; 71 | } 72 | } 73 | 74 | return true; 75 | } 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Error Management 80 | |-------------------------------------------------------------------------- 81 | */ 82 | 83 | /** 84 | * Returns the Order Error for Humans 85 | * 86 | * @param int $key 87 | * @return string|null 88 | */ 89 | public function getOrderErrorForHumans(int $key) 90 | { 91 | // First let's see if the item index exists 92 | $item = $this->detailOutput[$key] ?? null; 93 | 94 | // If the item exists and the errorCode also exists, return the translated 95 | // error code only if you can find it. Otherwise the script will proceed 96 | // and eventually return null since it did not exists from the get go. 97 | if ($item && $item->errorCode) { 98 | return self::getLoadedErrorList()[$this->listKey][$item->errorCode] ?? null; 99 | } 100 | return null; 101 | } 102 | 103 | /** 104 | * Alias for getOrderErrorForHumans() 105 | * 106 | * @param int $key 107 | * @return string|null 108 | */ 109 | public function getItemErrorForHumans(int $key) 110 | { 111 | return $this->getOrderErrorForHumans($key); 112 | } 113 | 114 | /* 115 | |-------------------------------------------------------------------------- 116 | | Order (Item) management 117 | |-------------------------------------------------------------------------- 118 | */ 119 | 120 | /** 121 | * Return all the orders 122 | * 123 | * @return array 124 | */ 125 | public function getOrders() 126 | { 127 | return $this->detailOutput; 128 | } 129 | 130 | /** 131 | * Alias for getOrders() 132 | * 133 | * @return mixed 134 | */ 135 | public function getItems() 136 | { 137 | return $this->getOrders(); 138 | } 139 | 140 | /** 141 | * Return only successful orders 142 | * 143 | * @return array 144 | */ 145 | public function getSuccessfulOrders() 146 | { 147 | $successful = []; 148 | 149 | foreach ($this->getItems() as $item) { 150 | if ($item->responseCode === 0) { 151 | $successful[] = $item; 152 | } 153 | } 154 | 155 | return $successful; 156 | } 157 | 158 | /** 159 | * Alias for getSuccessfulOrders() 160 | * 161 | * @return array 162 | */ 163 | public function getSuccessfulItems() 164 | { 165 | return $this->getSuccessfulOrders(); 166 | } 167 | 168 | /** 169 | * Return all failed Orders 170 | * 171 | * @return array 172 | */ 173 | public function getFailedOrders() 174 | { 175 | $successful = []; 176 | 177 | foreach ($this->getItems() as $item) { 178 | if ($item->responseCode !== 0) { 179 | $successful[] = $item; 180 | } 181 | } 182 | 183 | return $successful; 184 | } 185 | 186 | /** 187 | * Alias for getFailedOrders() 188 | * 189 | * @return array 190 | */ 191 | public function getFailedItems() 192 | { 193 | return $this->getFailedOrders(); 194 | } 195 | 196 | 197 | /** 198 | * Return the total amount of the whole transaction 199 | * 200 | * @return int 201 | */ 202 | public function getTotal() 203 | { 204 | $total = 0; 205 | 206 | foreach ($this->getItems() as $item) { 207 | $total += $item->amount; 208 | } 209 | 210 | return $total; 211 | } 212 | 213 | /** 214 | * Return only the total amount from successful items 215 | * 216 | * @return int 217 | */ 218 | public function getSuccessfulTotal() 219 | { 220 | $total = 0; 221 | 222 | foreach ($this->getSuccessfulItems() as $item) { 223 | $total += $item->amount; 224 | } 225 | 226 | return $total; 227 | } 228 | 229 | /** 230 | * Return only the total amount from failed items 231 | * 232 | * @return int 233 | */ 234 | public function getFailedTotal() 235 | { 236 | $total = 0; 237 | 238 | foreach ($this->getFailedItems() as $item) { 239 | $total += $item->amount; 240 | } 241 | 242 | return $total; 243 | } 244 | } -------------------------------------------------------------------------------- /tests/Unit/Responses/WebpayPlusMallResponseTest.php: -------------------------------------------------------------------------------- 1 | 'test-token' 15 | ]); 16 | 17 | $response->dynamicallySetSuccessStatus(); 18 | 19 | $this->assertTrue($response->isSuccess()); 20 | 21 | $response = new WebpayPlusMallResponse([]); 22 | 23 | $response->dynamicallySetSuccessStatus(); 24 | 25 | $this->assertFalse($response->isSuccess()); 26 | } 27 | 28 | public function testDynamicallySetSuccessStatusWithItems() 29 | { 30 | $response = new WebpayPlusMallResponse([ 31 | 'detailOutput' => [ 32 | (object)['responseCode' => 0], 33 | (object)['responseCode' => 0], 34 | (object)['responseCode' => 0], 35 | ] 36 | ]); 37 | 38 | $response->dynamicallySetSuccessStatus(); 39 | 40 | $this->assertTrue($response->isSuccess()); 41 | 42 | $response = new WebpayPlusMallResponse([ 43 | 'detailOutput' => [ 44 | (object)['responseCode' => 0], 45 | (object)['responseCode' => 1], 46 | (object)['responseCode' => 0], 47 | ] 48 | ]); 49 | 50 | $response->dynamicallySetSuccessStatus(); 51 | 52 | $this->assertFalse($response->isSuccess()); 53 | 54 | $response = new WebpayPlusMallResponse([ 55 | 'detailOutput' => (object)['responseCode' => 0] 56 | ]); 57 | 58 | $response->dynamicallySetSuccessStatus(); 59 | 60 | $this->assertTrue($response->isSuccess()); 61 | 62 | $response = new WebpayPlusMallResponse([ 63 | 'detailOutput' => (object)['responseCode' => 999] 64 | ]); 65 | 66 | $response->dynamicallySetSuccessStatus(); 67 | 68 | $this->assertFalse($response->isSuccess()); 69 | } 70 | 71 | public function testGetSuccessfulTotal() 72 | { 73 | $response = new WebpayPlusMallResponse([ 74 | 'detailOutput' => [ 75 | (object)['responseCode' => 0, 'amount' => 4990], 76 | (object)['responseCode' => 1, 'amount' => 4990], 77 | (object)['responseCode' => 0, 'amount' => 4990], 78 | ] 79 | ]); 80 | 81 | $this->assertEquals(4990 * 2, $response->getSuccessfulTotal()); 82 | } 83 | 84 | public function testGetSuccessfulOrdersOrGetSuccessfulItems() 85 | { 86 | $response = new WebpayPlusMallResponse([ 87 | 'detailOutput' => [ 88 | (object)['responseCode' => 0, 'amount' => 4990], 89 | (object)['responseCode' => 1, 'amount' => 4990], 90 | (object)['responseCode' => 0, 'amount' => 4990], 91 | ] 92 | ]); 93 | 94 | $this->assertCount(2, $response->getSuccessfulOrders()); 95 | $this->assertCount(2, $response->getSuccessfulItems()); 96 | } 97 | 98 | public function testGetTotal() 99 | { 100 | $response = new WebpayPlusMallResponse([ 101 | 'detailOutput' => [ 102 | (object)['responseCode' => 0, 'amount' => 4990], 103 | (object)['responseCode' => 1, 'amount' => 4990], 104 | (object)['responseCode' => 0, 'amount' => 4990], 105 | ] 106 | ]); 107 | 108 | $this->assertEquals(4990 * 3, $response->getTotal()); 109 | } 110 | 111 | public function testGetOrdersOrGetItems() 112 | { 113 | $response = new WebpayPlusMallResponse([ 114 | 'detailOutput' => $array = [ 115 | (object)['responseCode' => 0, 'amount' => 4990], 116 | (object)['responseCode' => 1, 'amount' => 4990], 117 | (object)['responseCode' => 0, 'amount' => 4990], 118 | ] 119 | ]); 120 | 121 | $this->assertEquals($array, $response->getOrders()); 122 | $this->assertEquals($array, $response->getItems()); 123 | } 124 | 125 | public function testGetOrderErrorForHumansOrGetItemErrorForHumans() 126 | { 127 | $response = new WebpayPlusMallResponse([ 128 | 'detailOutput' => [ 129 | (object)['responseCode' => 0, 'amount' => 4990], 130 | (object)['responseCode' => 1, 'errorCode' => 18, 'amount' => 4990], 131 | (object)['responseCode' => 0, 'amount' => 4990], 132 | (object)['responseCode' => 1, 'errorCode' => 99999, 'amount' => 4990], 133 | ] 134 | ]); 135 | 136 | $this->assertEquals('ERR_SERVIDOR_COMERCIO', $response->getOrderErrorForHumans(1)); 137 | $this->assertEquals('ERR_SERVIDOR_COMERCIO', $response->getItemErrorForHumans(1)); 138 | $this->assertNull($response->getOrderErrorForHumans(3)); 139 | $this->assertNull($response->getOrderErrorForHumans(5)); 140 | } 141 | 142 | public function testGetFailedOrdersOrGetFailedItems() 143 | { 144 | $failed = [ 145 | (object)['responseCode' => 1, 'errorCode' => 18, 'amount' => 4990], 146 | (object)['responseCode' => 1, 'errorCode' => 1, 'amount' => 4990], 147 | ]; 148 | 149 | $response = new WebpayPlusMallResponse([ 150 | 'detailOutput' => [ 151 | (object)['responseCode' => 0, 'amount' => 4990], 152 | (object)['responseCode' => 1, 'errorCode' => 18, 'amount' => 4990], 153 | (object)['responseCode' => 0, 'amount' => 4990], 154 | (object)['responseCode' => 1, 'errorCode' => 1, 'amount' => 4990], 155 | ] 156 | ]); 157 | 158 | $this->assertEquals($failed, $response->getFailedOrders()); 159 | $this->assertEquals($failed, $response->getFailedItems()); 160 | } 161 | 162 | public function testGetFailedTotal() 163 | { 164 | $response = new WebpayPlusMallResponse([ 165 | 'detailOutput' => [ 166 | (object)['responseCode' => 0, 'amount' => 4990], 167 | (object)['responseCode' => 1, 'errorCode' => 18, 'amount' => 1990], 168 | (object)['responseCode' => 0, 'amount' => 4990], 169 | (object)['responseCode' => 1, 'errorCode' => 1, 'amount' => 1990], 170 | ] 171 | ]); 172 | 173 | $this->assertEquals(1990 * 2, $response->getFailedTotal()); 174 | } 175 | } 176 | --------------------------------------------------------------------------------