# Payment Gateways & Modern Frameworks

# Modern Payment Gateways

# PAYA Gateway

https://www.payagateway.com/developer-portal.html

# Authorize.net

https://developer.authorize.net/

# Stripe

https://docs.stripe.com/

# Chapter

# DigitalOcean Hosting

[https://www.digitalocean.com/?refcode=a7e160320b06&amp;utm\_campaign=Referral\_Invite&amp;utm\_medium=Referral\_Program&amp;utm\_source=CopyPaste](https://www.digitalocean.com/?refcode=a7e160320b06&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=CopyPaste)

you can get 2 month for free on DigitalOcean with a coupon code, and you get a proper server. here's the link: https://m.do.co/c/a7e160320b06

# alpinejs - Your new, lightweight, JavaScript framework.

https://alpinejs.dev/start-here

# Inertia modern monolith

https://inertiajs.com/

# Chapter

# Livewire 3.x.

https://laravel-livewire.com/docs/2.x/quickstart

# Pest PHP Testing Framework

https://pestphp.com/docs/installation

# Filament Documentation

https://filamentphp.com/docs

# Livewire v3, Alpine.js, and Inertia.js.

<div class="Y3BBE" data-hveid="CAEQAA" data-processed="true" data-sfc-cp="" id="bkmrk-livewire-v3%2C%C2%A0alpine." jsaction="rcuQ6b:&KtqS4b_8|npT2md" jscontroller="zcfIf" jsuid="KtqS4b_8" style="font-family: 'Google Sans', Roboto, Arial, sans-serif; font-size: 16px; line-height: 24px; overflow-wrap: break-word; margin: 0px 0px 20px; color: rgb(10, 10, 10); font-weight: 400; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><span class="T286Pc" data-sfc-cp="" style="overflow-wrap: break-word;"><span data-sfc-cp="">[Livewire v3](https://livewire.laravel.com/)</span>, <span data-sfc-cp="">[Alpine.js](https://alpinejs.dev/)</span>, and <span data-sfc-cp="">[Inertia.js](https://inertiajs.com/)</span> are tools used to build modern, dynamic web applications, often within the Laravel ecosystem, but they serve different primary purposes and use different architectural approaches</span>.<span class="uJ19be notranslate" data-wiz-uids="KtqS4b_g,KtqS4b_h"><span class="vKEkVd" data-animation-atomic="" style="white-space: nowrap; position: relative;"> <button aria-label="View related links" class="rBl3me" data-amic="true" data-icl-uuid="1e724cb7-ae33-4e9d-b3bd-a520f52c4f49" data-ved="2ahUKEwiN3OzU8t6QAxWJyzgGHVpYL-4Qye0OegQIARAE" data-wiz-attrbind="disabled=KtqS4b_g_C5gNJc;class=KtqS4b_g_UpSNec;" style="margin: 0px 6px 0px 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(229, 237, 255); border: none; border-radius: 10px; height: 20px; padding: 0px; width: 28px; position: relative; outline: 0px; cursor: pointer;" tabindex="0"><span class="wiMplc ofC0Ud" style="color: rgb(0, 29, 53); display: inline-block; transform: rotate(135deg);"><svg fill="currentColor" focusable="false" height="12px" style="margin-top: 3px;" viewbox="0 0 24 24" width="12px" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></span></button></span></span></div><div class="Fsg96" data-processed="true" data-sfc-cp="" id="bkmrk-" jsaction="rcuQ6b:&KtqS4b_k|npT2md" jscontroller="KHhJQ" jsuid="KtqS4b_k" style="color: rgb(10, 10, 10); font-family: 'Google Sans', Roboto, Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">  
</div><div class="Fv6NCb" data-processed="true" data-sfc-cp="" data-ved="2ahUKEwiN3OzU8t6QAxWJyzgGHVpYL-4Q-q4QegQIAxAA" data-wiz-uids="KtqS4b_18" id="bkmrk-feature%C2%A0-livewire-v3" jsaction="rcuQ6b:&KtqS4b_18|npT2md" jscontroller="kbUand" jsuid="KtqS4b_18" style="overflow: auto; width: calc(100% + 0px); box-sizing: border-box; scrollbar-width: none; margin: 16px 0px; color: rgb(10, 10, 10); font-family: 'Google Sans', Roboto, Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><table border="1" class="NRefec" data-animation-nesting="" data-processed="true" style="border: medium; border-collapse: collapse; table-layout: auto; width: 100%; height: 100%;"><tbody data-processed="true"><tr class="cZCYO" data-processed="true" data-sfc-cp=""><th class="iry6k" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; padding: 0px 10px 12px 0px; text-align: left; font-weight: bold; font-size: 14px; width: 209.75px;">Feature<span class="uJ19be notranslate" data-processed="true" data-wiz-uids="KtqS4b_1b,KtqS4b_1c"><span class="vKEkVd" data-animation-atomic="" data-processed="true" style="white-space: nowrap; position: relative;"> <button aria-label="View related links" class="rBl3me" data-amic="true" data-icl-uuid="fc288534-cf5c-4abf-9323-d111ec3759c3" data-processed="true" data-ved="2ahUKEwiN3OzU8t6QAxWJyzgGHVpYL-4Qye0OegQIAxAB" data-wiz-attrbind="disabled=KtqS4b_1b_C5gNJc;class=KtqS4b_1b_UpSNec;" style="margin: 0px 6px 0px 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgb(229, 237, 255); border: none; border-radius: 10px; height: 20px; padding: 0px; width: 28px; position: relative; outline: 0px; cursor: pointer;" tabindex="0"><span class="wiMplc ofC0Ud" data-processed="true" style="color: rgb(0, 29, 53); display: inline-block; transform: rotate(135deg);"><svg fill="currentColor" focusable="false" height="12px" style="margin-top: 3px;" viewbox="0 0 24 24" width="12px" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></span></button></span></span></th><th class="iry6k" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; padding: 0px 10px 12px; text-align: left; font-weight: bold; font-size: 14px; width: 124.383px;">Livewire v3</th><th class="iry6k" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; padding: 0px 10px 12px; text-align: left; font-weight: bold; font-size: 14px; width: 105.317px;">Alpine.js</th><th class="iry6k" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; padding: 0px 0px 12px 10px; text-align: left; font-weight: bold; font-size: 14px; width: 94.8333px;"><span class="T286Pc" data-processed="true" data-sfc-cp="" style="overflow-wrap: break-word;">Inertia.js</span></th></tr><tr class="cZCYO" data-processed="true" data-sfc-cp=""><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px 12px 0px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 329.383px;">**Primary Use**</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 159.583px;">Building full-stack, dynamic interfaces with minimal JavaScript, using PHP and Laravel Blade.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 128.217px;">Adding light, client-side interactivity (dropdowns, modals) directly in the HTML markup.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 0px 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 111.75px;">Connecting a server-side framework (like Laravel) to a client-side SPA framework (Vue, React, Svelte) without building a full API.</td></tr><tr class="cZCYO" data-processed="true" data-sfc-cp=""><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px 12px 0px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 379.117px;">**Architecture**</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 171.95px;">Server-side rendering with AJAX calls to the server for updates, which then morph the DOM.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 135.983px;">Client-side, uses attributes in HTML to add behavior; no virtual DOM.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 0px 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 117.367px;">Client-side rendering (using Vue/React/Svelte), but leverages server-side routing and controllers.</td></tr><tr class="cZCYO" data-processed="true" data-sfc-cp=""><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px 12px 0px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 395.417px;">**JavaScript Needed?**</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 175.783px;">Minimal to none for core functionality; most logic is in PHP.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 138.367px;">Used directly in HTML via directives, minimal separate JS files needed.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 0px 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 119.083px;">Requires writing code in a full JavaScript framework (Vue, React, or Svelte).</td></tr><tr class="cZCYO" data-processed="true" data-sfc-cp=""><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px 12px 0px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 400.35px;">**SEO**</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 176.933px;">Excellent by default due to server-side rendering.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 139.067px;">Inherently SEO-friendly as it enhances existing HTML.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 0px 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 119.583px;">Requires setting up server-side rendering (SSR) for optimal SEO.</td></tr><tr class="cZCYO" data-processed="true" data-sfc-cp=""><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px 12px 0px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 401.817px;">**Best For**</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 177.267px;">Developers who prefer working primarily with PHP/Blade and want an SPA-like experience.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 139.283px;">Adding small, instant UI tweaks and interactions to a standard server-rendered application.</td><td class="cOeeGf" colspan="undefined" data-processed="true" data-sfc-cp="" style="border-bottom: 1.2px solid rgb(169, 172, 170); min-width: 4em; vertical-align: top; color: rgb(10, 10, 10); padding: 12px 0px 12px 10px; font-family: 'Google Sans', Arial, sans-serif; font-size: 14px; line-height: 18px; font-weight: 400; width: 119.733px;">Developers already proficient in Vue, React, or Svelte who want to build a monolithic SPA using Laravel as the backend/router.</td></tr></tbody></table>

</div>

# Gemini Developer API

https://ai.google.dev/gemini-api/docs

# Express.js Tutorial

[https://www.geeksforgeeks.org/node-js/express-js/](https://www.geeksforgeeks.org/node-js/express-js/)

[https://github.com/takuyadev/node-express-typescript](https://github.com/takuyadev/node-express-typescript)

[https://github.com/bezkoder/node-js-jwt-auth](https://github.com/bezkoder/node-js-jwt-auth)

https://github.com/bahricanyesil/nodejs-starter-template

# Laravel Authorize.Net

A comprehensive Laravel package for seamless integration with Authorize.Net payment gateway. This package provides an elegant, fluent interface for managing customer profiles, payment methods, transactions, subscriptions, and more.

## Features

- **Customer Profile Management** - Create and manage customer profiles on Authorize.Net
- **Payment Profile Management** - Store payment methods securely without PCI compliance requirements
- **Direct Card Transactions** - Process one-time card payments
- **Recurring Subscriptions** - Create and manage subscription payments
- **Transaction Management** - Process charges, refunds, and query transactions
- **Eloquent Models** - Built-in models for local storage of payment profiles
- **Type-Safe** - Full PHP 8.1+ type hints and return types
- **Laravel 10/11/12 Compatible** - Works with modern Laravel versions
- **Well-Tested** - Comprehensive test coverage

## Requirements

- PHP &gt;= 8.1
- Laravel &gt;= 10.0
- Authorize.Net account (sandbox or production)
- cURL extension enabled

## Installation

Install the package via Composer:

```bash
composer require squareetlabs/laravel-authorizenet

```

### Publish Configuration

Publish the configuration file (optional):

```bash
php artisan vendor:publish --tag=authorizenet-config

```

### Run Migrations

The package requires database tables to store customer and payment profiles. Run the migrations:

```bash
php artisan migrate

```

This will create two tables: - `user_gateway_profiles` - Stores Authorize.Net customer profile IDs - `user_payment_profiles` - Stores payment method information

### Setup User Model

Add the `ANetPayments` trait to your User model:

```php
<?php

namespace App\Models;

use Squareetlabs\AuthorizeNet\Traits\ANetPayments;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use ANetPayments;
    
    // ... your model code
}

```

## Configuration

Add your Authorize.Net credentials to your `.env` file:

```env
AUTHORIZE_NET_LOGIN_ID=your_login_id
AUTHORIZE_NET_CLIENT_KEY=your_client_key
AUTHORIZE_NET_TRANSACTION_KEY=your_transaction_key
AUTHORIZE_NET_ENVIRONMENT=sandbox  # or 'production'

```

You can obtain these credentials from your Authorize.Net Merchant Interface: - **Sandbox**: https://sandbox.authorize.net - **Production**: https://account.authorize.net

Navigate to **Settings &gt; Security Settings &gt; API Credentials &amp; Keys** to find your credentials.

## Basic Usage

Once configured, you can access Authorize.Net functionality through the `anet()` method on your User model:

```php
$user = User::find(1);

// All Authorize.Net operations are available via $user->anet()
$user->anet()->createCustomerProfile();

```

## Customer Profiles

Customer profiles are required before you can store payment methods. Authorize.Net uses customer profiles to securely store payment information without requiring PCI compliance on your end.

### Create a Customer Profile

```php
$response = $user->anet()->createCustomerProfile();

// Access the profile ID
$profileId = $response->getCustomerProfileId();

```

### Get Customer Profile ID

```php
$profileId = $user->anet()->getCustomerProfileId();

```

The customer profile ID is automatically stored in your database using the `UserGatewayProfile` model.

## Payment Profiles

Payment profiles allow you to store payment methods securely without handling sensitive card data. This is achieved through Authorize.Net's Accept.js, which sends payment data directly to Authorize.Net.

### Creating a Payment Profile with Accept.js

**Frontend (JavaScript):**

```javascript
// Include Accept.js library
<script src="https://jstest.authorize.net/v1/Accept.js"></script>

// Collect payment data and send to Authorize.Net
Accept.dispatchData(secureDataRequest, function (response) {
    if (response.messages.resultCode === "Ok") {
        // Send opaque data to your server
        fetch('/api/payment-profiles', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
            },
            body: JSON.stringify({
                opaqueData: {
                    dataValue: response.opaqueData.dataValue,
                    dataDescriptor: response.opaqueData.dataDescriptor
                },
                source: {
                    last_4: '1234',
                    brand: 'VISA',
                    type: 'card'
                }
            })
        });
    }
});

```

**Backend (Laravel):**

```php
use Illuminate\Http\Request;

public function storePaymentProfile(Request $request)
{
    $user = auth()->user();
    
    $response = $user->anet()->createPaymentProfile(
        $request->opaqueData,
        $request->source
    );
    
    if ($response->getCustomerPaymentProfileId()) {
        return response()->json([
            'success' => true,
            'payment_profile_id' => $response->getCustomerPaymentProfileId()
        ]);
    }
    
    return response()->json(['success' => false], 422);
}

```

### Get Payment Profiles

```php
// Get all payment methods
$paymentMethods = $user->anet()->getPaymentMethods();

// Get only card payment profiles
$cards = $user->anet()->getPaymentCardProfiles();

// Get only bank account payment profiles
$banks = $user->anet()->getPaymentBankProfiles();

// Get just the payment profile IDs
$profileIds = $user->anet()->getPaymentProfiles();

```

### Using Eloquent Models

You can also work directly with the Eloquent models:

```php
use Squareetlabs\AuthorizeNet\Models\UserPaymentProfile;

// Get all payment profiles for a user
$profiles = UserPaymentProfile::where('user_id', $user->id)->get();

// Get only cards using scope
$cards = UserPaymentProfile::where('user_id', $user->id)->cards()->get();

// Get only banks using scope
$banks = UserPaymentProfile::where('user_id', $user->id)->banks()->get();

// Access model properties
foreach ($profiles as $profile) {
    echo $profile->payment_profile_id;
    echo $profile->last_4;
    echo $profile->brand;
    echo $profile->type; // 'card' or 'bank'
}

```

## Charging Payment Profiles

Once you have a payment profile, you can charge it:

```php
// Charge $19.99 (amount in cents)
$response = $user->anet()->charge(1999, $paymentProfileId);

// Check if transaction was approved
if ($response->getMessages()->getResultCode() === 'Ok') {
    $transactionResponse = $response->getTransactionResponse();
    
    if ($transactionResponse->getResponseCode() === '1') {
        $transactionId = $transactionResponse->getTransId();
        // Transaction successful
    }
}

```

## Refunds

Refund a previous transaction:

```php
// Refund $10.00 (amount in cents)
$response = $user->anet()->refund(
    1000,                    // Amount in cents
    $refTransId,            // Reference transaction ID from charge
    $paymentProfileId       // Payment profile ID
);

```

## Direct Card Transactions

For one-time payments without storing payment methods, you can process direct card transactions:

```php
$response = $user->anet()
    ->card()
    ->setNumbers(4111111111111111)
    ->setCVV(123)
    ->setNameOnCard('John Doe')
    ->setExpMonth(12)
    ->setExpYear(2025)
    ->setAmountInCents(1000)  // $10.00
    ->charge();

// Check transaction result
if ($response->getMessages()->getResultCode() === 'Ok') {
    $transactionResponse = $response->getTransactionResponse();
    $transactionId = $transactionResponse->getTransId();
}

```

### Card Service Methods

```php
$card = $user->anet()->card();

// Set card information
$card->setNumbers(4111111111111111);
$card->setCVV(123);
$card->setNameOnCard('John Doe');
$card->setExpMonth(12);              // Integer: 1-12
$card->setExpYear(2025);             // Integer or 2-digit year
$card->setBrand('VISA');              // Optional
$card->setType('Credit');            // Optional

// Set amount
$card->setAmountInCents(1000);       // $10.00
$card->setAmountInDollars(10.00);    // Alternative method

// Process charge
$response = $card->charge();

```

## Subscriptions

Create and manage recurring subscription payments:

### Create a Subscription

```php
$response = $user->anet()->subscription()->create([
    'name' => 'Monthly Premium Plan',
    'startDate' => '2024-01-15',
    'totalOccurrences' => 12,
    'trialOccurrences' => 1,
    'intervalLength' => 30,
    'intervalLengthUnit' => 'days',  // 'days' or 'months'
    'amountInDollars' => 29.99,
    'trialAmountInDollars' => 0.00,
    'cardNumber' => 4111111111111111,
    'cardExpiry' => '2025-12',
    'invoiceNumber' => 'INV-001',
    'subscriptionDescription' => 'Monthly premium subscription',
    'customerFirstName' => 'John',
    'customerLastName' => 'Doe'
]);

$subscriptionId = $response->getSubscriptionId();

```

### Get Subscription

```php
$subscription = $user->anet()->subscription()->get($subscriptionId);

```

### Update Subscription

```php
$response = $user->anet()->subscription()->update($subscriptionId, [
    'cardNumber' => 4111111111111111,
    'cardExpiry' => '2026-12'
]);

```

### Cancel Subscription

```php
$response = $user->anet()->subscription()->cancel($subscriptionId);

```

### Get Subscription Status

```php
$response = $user->anet()->subscription()->getStatus($subscriptionId);

```

### List Subscriptions

```php
$subscriptions = $user->anet()->subscription()->getList([
    'orderBy' => 'id',
    'orderDescending' => false,
    'limit' => 100,
    'offset' => 1,
    'searchType' => 'subscriptionActive'  // 'subscriptionActive' or 'subscriptionInactive'
]);

```

### Subscription Aliases

You can use any of these methods to access the subscription service:

```php
$user->anet()->subscription();
$user->anet()->subs();
$user->anet()->recurring();

```

## Transaction Management

Work with transaction responses to check status and retrieve information:

```php
// After charging a payment profile
$chargeResponse = $user->anet()->charge(1000, $paymentProfileId);

// Create transaction service instance
$transaction = $user->anet()->transactions($chargeResponse);

// Check if transaction was approved
if ($transaction->isApproved()) {
    // Transaction was successful
}

// Check if request was successful (doesn't mean transaction was approved)
if ($transaction->isRequestSuccessful()) {
    // Request reached Authorize.Net successfully
}

// Get transaction ID
$transactionId = $transaction->getId();

// Access transaction response methods
$transaction->getRefTransID();
$transaction->getResponseCode();
// ... and other transaction response methods

```

### Get Transactions by Batch ID

```php
$transactions = $user->anet()
    ->transactions($transactionResponse)
    ->get($batchId);

```

## Working with Transaction Responses

All transaction methods return a `CreateTransactionResponse` object. Here's how to work with it:

```php
$response = $user->anet()->charge(1000, $paymentProfileId);

// Check overall result
if ($response->getMessages()->getResultCode() === 'Ok') {
    $transactionResponse = $response->getTransactionResponse();
    
    // Check transaction response code
    // 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review
    if ($transactionResponse->getResponseCode() === '1') {
        // Transaction approved
        $transactionId = $transactionResponse->getTransId();
        $authCode = $transactionResponse->getAuthCode();
        $accountNumber = $transactionResponse->getAccountNumber(); // Last 4 digits
    } else {
        // Transaction declined or error
        $errors = $transactionResponse->getErrors();
        foreach ($errors as $error) {
            echo $error->getErrorCode() . ': ' . $error->getErrorText();
        }
    }
}

```

## Eloquent Models

The package provides two Eloquent models for working with stored data:

### UserGatewayProfile

Represents a customer profile stored locally:

```php
use Squareetlabs\AuthorizeNet\Models\UserGatewayProfile;

// Get customer profile for user
$profile = UserGatewayProfile::where('user_id', $user->id)->first();

// Access properties
$profile->profile_id;  // Authorize.Net customer profile ID
$profile->user_id;

```

### UserPaymentProfile

Represents a payment method stored locally:

```php
use Squareetlabs\AuthorizeNet\Models\UserPaymentProfile;

// Relationships
$profile->user;  // BelongsTo User model

// Scopes
UserPaymentProfile::cards()->get();  // Only card payment profiles
UserPaymentProfile::banks()->get();  // Only bank payment profiles

// Access properties
$profile->payment_profile_id;  // Authorize.Net payment profile ID
$profile->last_4;              // Last 4 digits of card/account
$profile->brand;               // Card brand (VISA, MasterCard, etc.)
$profile->type;                // 'card' or 'bank'

```

## Environment Configuration

The package automatically uses the appropriate environment based on your Laravel app environment:

- **Local/Testing**: Uses Authorize.Net Sandbox
- **Production**: Uses Authorize.Net Production

You can override this by setting `AUTHORIZE_NET_ENVIRONMENT` in your `.env` file:

```env
AUTHORIZE_NET_ENVIRONMENT=sandbox  # or 'production'

```

## Error Handling

Always wrap Authorize.Net operations in try-catch blocks:

```php
try {
    $response = $user->anet()->charge(1000, $paymentProfileId);
    
    if ($response->getMessages()->getResultCode() === 'Ok') {
        $transactionResponse = $response->getTransactionResponse();
        
        if ($transactionResponse->getResponseCode() === '1') {
            // Success
        } else {
            // Transaction declined
            $errors = $transactionResponse->getErrors();
            // Handle errors
        }
    } else {
        // Request failed
        $messages = $response->getMessages()->getMessage();
        // Handle messages
    }
} catch (\Exception $e) {
    // Handle exception
    Log::error('Authorize.Net Error: ' . $e->getMessage());
}

```

## Testing

### Running Package Tests

The package includes a comprehensive test suite. To run the tests:

```bash
composer test
# or
vendor/bin/phpunit tests/

```

### Test Coverage

The package includes tests for:

- **Unit Tests** - Models, Services, and core functionality (all passing)
- **Integration Tests** - API interactions with Authorize.Net (require valid credentials)
- **Model Tests** - Eloquent models and relationships (all passing)
- **Service Tests** - Payment processing, subscriptions, and transactions

### Test Environment Setup

For testing, you need to configure your `.env` file with Authorize.Net sandbox credentials:

```env
AUTHORIZE_NET_ENVIRONMENT=sandbox
AUTHORIZE_NET_LOGIN_ID=your_sandbox_login_id
AUTHORIZE_NET_TRANSACTION_KEY=your_sandbox_transaction_key
AUTHORIZE_NET_CLIENT_KEY=your_sandbox_client_key

```

**Note**: Some integration tests require valid Authorize.Net sandbox credentials and will fail if credentials are invalid or missing. This is expected behavior as these tests verify actual API connectivity.

### Testing in Your Application

When testing your own application that uses this package:

#### Option 1: Use Authorize.Net Sandbox (Recommended)

Configure your test environment to use Authorize.Net's sandbox:

```env
# .env.testing
AUTHORIZE_NET_ENVIRONMENT=sandbox
AUTHORIZE_NET_LOGIN_ID=your_sandbox_login_id
AUTHORIZE_NET_TRANSACTION_KEY=your_sandbox_transaction_key
AUTHORIZE_NET_CLIENT_KEY=your_sandbox_client_key

```

#### Option 2: Mock Authorize.Net Responses

Use PHPUnit's mocking capabilities to mock API responses:

```php
use PHPUnit\Framework\TestCase;
use Squareetlabs\AuthorizeNet\Services\CustomerProfileService;
use net\authorize\api\contract\v1\CreateCustomerProfileResponse;

class PaymentTest extends TestCase
{
    public function test_customer_profile_creation()
    {
        // Mock the service
        $service = $this->createMock(CustomerProfileService::class);
        
        // Create mock response
        $mockResponse = new CreateCustomerProfileResponse();
        // ... configure mock response
        
        $service->expects($this->once())
            ->method('create')
            ->willReturn($mockResponse);
            
        // Test your code
    }
}

```

#### Option 3: Use Feature Flags

Skip actual API calls during testing:

```php
if (app()->environment('testing')) {
    // Return mock data instead of calling Authorize.Net
    return $this->mockAuthorizeNetResponse();
}

// Normal API call
return $user->anet()->charge(1000, $paymentProfileId);

```

### Test Database Setup

The package tests use an in-memory SQLite database. The package automatically creates the necessary tables during testing. **Note**: The package does not create a `users` table migration - your application should already have this table.

### Test Results

Current test status: - **Total Tests**: 89 - **Passing**: ~53 (unit tests and model tests) - **Integration Tests**: Require valid Authorize.Net credentials - **Model Tests**: 100% passing (10/10) - **Service Tests**: Unit tests passing, integration tests require API credentials

### Best Practices for Testing

1. **Use Sandbox Environment**: Always use Authorize.Net sandbox credentials for testing
2. **Mock External Calls**: For unit tests, mock Authorize.Net API responses
3. **Test Error Handling**: Test both success and failure scenarios
4. **Isolate Tests**: Each test should be independent and not rely on previous test data
5. **Use Test Database**: Always use a separate test database, never test against production data

## API Reference

**Authorize.Net Documentation**<span style="color: rgb(0, 0, 0); font-family: helvetica, sans-serif, arial, helvetica; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(252, 252, 252); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">: https://developer.authorize.net/</span>

### ANet Class Methods

```php
// Customer Profiles
$user->anet()->createCustomerProfile();
$user->anet()->getCustomerProfileId();

// Payment Profiles
$user->anet()->createPaymentProfile($opaqueData, $source);
$user->anet()->getPaymentProfiles();
$user->anet()->getPaymentMethods();
$user->anet()->getPaymentCardProfiles();
$user->anet()->getPaymentBankProfiles();

// Transactions
$user->anet()->charge($cents, $paymentProfileId);
$user->anet()->refund($cents, $refTransId, $paymentProfileId);
$user->anet()->transactions($transactionResponse);
$user->anet()->card();

// Subscriptions
$user->anet()->subscription();
$user->anet()->subs();
$user->anet()->recurring();
```