Merge pull request #10052 from turbo124/v5-develop

Fixes for product sales export
This commit is contained in:
David Bomba 2024-09-29 14:33:45 +10:00 committed by GitHub
commit 9e78ead76c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 331 additions and 131 deletions

View File

@ -23,7 +23,7 @@ use League\Csv\Writer;
class ProductSalesExport extends BaseExport class ProductSalesExport extends BaseExport
{ {
public string $date_key = 'created_at'; public string $date_key = 'date';
/** @var Collection<\App\Models\Product> $products*/ /** @var Collection<\App\Models\Product> $products*/
protected Collection $products; protected Collection $products;

View File

@ -255,7 +255,7 @@ abstract class QueryFilters
public function client_id(string $client_id = ''): Builder public function client_id(string $client_id = ''): Builder
{ {
if (strlen($client_id) == 0) { if (strlen($client_id) == 0 || !in_array('vendor_id', \Illuminate\Support\Facades\Schema::getColumnListing($this->builder->getModel()->getTable()))) {
return $this->builder; return $this->builder;
} }
@ -264,7 +264,7 @@ abstract class QueryFilters
public function vendor_id(string $vendor_id = ''): Builder public function vendor_id(string $vendor_id = ''): Builder
{ {
if (strlen($vendor_id) == 0) { if (strlen($vendor_id) == 0 || !in_array('vendor_id', \Illuminate\Support\Facades\Schema::getColumnListing($this->builder->getModel()->getTable()))) {
return $this->builder; return $this->builder;
} }

View File

@ -251,6 +251,12 @@ class CompanyGatewayController extends BaseController
$company_gateway->driver()->init()->settings()->updateSettings(); $company_gateway->driver()->init()->settings()->updateSettings();
})->afterResponse(); })->afterResponse();
$config = $company_gateway->getConfig();
$config->visa = true;
$config->mastercard = true;
$company_gateway->setConfig($config);
$company_gateway->save();
break; break;
default: default:

View File

@ -93,11 +93,13 @@ class StoreInvoiceRequest extends Request
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
if(\Illuminate\Support\Facades\Cache::has($this->ip()."|INVOICE|".$this->input('client_id', '')."|".$user->company()->company_key)) { $client_id = is_string($this->input('client_id', '')) ? $this->input('client_id') : '';
if(\Illuminate\Support\Facades\Cache::has($this->ip()."|INVOICE|".$client_id."|".$user->company()->company_key)) {
usleep(200000); usleep(200000);
} }
\Illuminate\Support\Facades\Cache::put($this->ip()."|INVOICE|".$this->input('client_id', '')."|".$user->company()->company_key,1); \Illuminate\Support\Facades\Cache::put($this->ip()."|INVOICE|".$client_id."|".$user->company()->company_key,1);
$input = $this->all(); $input = $this->all();

View File

@ -80,11 +80,13 @@ class StorePaymentRequest extends Request
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
if(\Illuminate\Support\Facades\Cache::has($this->ip()."|".$this->input('amount', 0)."|".$this->input('client_id', '')."|".$user->company()->company_key)) { $client_id = is_string($this->input('client_id', '')) ? $this->input('client_id') : '';
if(\Illuminate\Support\Facades\Cache::has($this->ip()."|".$this->input('amount', 0)."|".$client_id."|".$user->company()->company_key)) {
throw new DuplicatePaymentException('Duplicate request.', 429); throw new DuplicatePaymentException('Duplicate request.', 429);
} }
\Illuminate\Support\Facades\Cache::put(($this->ip()."|".$this->input('amount', 0)."|".$this->input('client_id', '')."|".$user->company()->company_key), true, 1); \Illuminate\Support\Facades\Cache::put(($this->ip()."|".$this->input('amount', 0)."|".$client_id."|".$user->company()->company_key), true, 1);
$input = $this->all(); $input = $this->all();
@ -105,7 +107,7 @@ class StorePaymentRequest extends Request
$input['invoices'][$key]['invoice_id'] = $this->decodePrimaryKey($value['invoice_id']); $input['invoices'][$key]['invoice_id'] = $this->decodePrimaryKey($value['invoice_id']);
} }
if (array_key_exists('amount', $value)) { if (array_key_exists('amount', $value) && is_numeric($value['amount'])) {
$invoices_total += $value['amount']; $invoices_total += $value['amount'];
} }
} }
@ -119,7 +121,10 @@ class StorePaymentRequest extends Request
foreach ($input['credits'] as $key => $value) { foreach ($input['credits'] as $key => $value) {
if (isset($value['credit_id']) && is_string($value['credit_id'])) { if (isset($value['credit_id']) && is_string($value['credit_id'])) {
$input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($value['credit_id']); $input['credits'][$key]['credit_id'] = $this->decodePrimaryKey($value['credit_id']);
$credits_total += $value['amount'];
if (array_key_exists('amount', $value) && is_numeric($value['amount'])) {
$credits_total += $value['amount'];
}
} }
} }
} }

View File

@ -100,7 +100,7 @@ class UpdatePaymentRequest extends Request
public function messages() public function messages()
{ {
return [ return [
'distinct' => 'Attemping duplicate payment on the same invoice Invoice', 'distinct' => 'Attemping duplicate payment on the same Invoice',
]; ];
} }
} }

View File

@ -62,8 +62,8 @@ class StoreSchedulerRequest extends Request
'parameters' => 'bail|array', 'parameters' => 'bail|array',
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()], 'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom,all', 'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom,all',
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'], 'parameters.start_date' => ['bail', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'], 'parameters.end_date' => ['bail', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'], 'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
'parameters.entity_id' => ['bail', 'sometimes', 'string'], 'parameters.entity_id' => ['bail', 'sometimes', 'string'],
'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report','in:vendor,purchase_order_item,purchase_order,ar_detailed,ar_summary,client_balance,tax_summary,profitloss,client_sales,user_sales,product_sales,activity,activities,client,clients,client_contact,client_contacts,credit,credits,document,documents,expense,expenses,invoice,invoices,invoice_item,invoice_items,quote,quotes,quote_item,quote_items,recurring_invoice,recurring_invoices,payment,payments,product,products,task,tasks'], 'parameters.report_name' => ['bail','sometimes', 'string', 'required_if:template,email_report','in:vendor,purchase_order_item,purchase_order,ar_detailed,ar_summary,client_balance,tax_summary,profitloss,client_sales,user_sales,product_sales,activity,activities,client,clients,client_contact,client_contacts,credit,credits,document,documents,expense,expenses,invoice,invoices,invoice_item,invoice_items,quote,quotes,quote_item,quote_items,recurring_invoice,recurring_invoices,payment,payments,product,products,task,tasks'],

View File

@ -36,6 +36,7 @@ class InvoiceTransformer extends BaseTransformer
$invoiceStatusMap = [ $invoiceStatusMap = [
'sent' => Invoice::STATUS_SENT, 'sent' => Invoice::STATUS_SENT,
'draft' => Invoice::STATUS_DRAFT, 'draft' => Invoice::STATUS_DRAFT,
'paid' => Invoice::STATUS_PAID,
]; ];
$transformed = [ $transformed = [

View File

@ -11,31 +11,32 @@
namespace App\Jobs\Mail; namespace App\Jobs\Mail;
use App\DataMapper\Analytics\EmailFailure; use App\Models\User;
use App\DataMapper\Analytics\EmailSuccess; use App\Utils\Ninja;
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
use App\Events\Payment\PaymentWasEmailedAndFailed;
use App\Jobs\Util\SystemLogger;
use App\Libraries\Google\Google;
use App\Libraries\MultiDB;
use App\Models\ClientContact;
use App\Models\Company; use App\Models\Company;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
use App\Models\SystemLog; use App\Models\SystemLog;
use App\Models\User; use App\Libraries\MultiDB;
use App\Utils\Ninja; use App\Models\ClientContact;
use App\Utils\Traits\MakesHash;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use App\Jobs\Util\SystemLogger;
use App\Utils\Traits\MakesHash;
use App\Libraries\Google\Google;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Cache;
use Illuminate\Queue\SerializesModels;
use Postmark\Models\PostmarkException;
use Turbo124\Beacon\Facades\LightLogs;
use Illuminate\Queue\InteractsWithQueue;
use GuzzleHttp\Exception\ClientException;
use App\DataMapper\Analytics\EmailFailure;
use App\DataMapper\Analytics\EmailSuccess;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use App\Events\Invoice\InvoiceWasEmailedAndFailed;
use Illuminate\Queue\SerializesModels; use App\Events\Payment\PaymentWasEmailedAndFailed;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Mail;
use Turbo124\Beacon\Facades\LightLogs;
/*Multi Mailer implemented*/ /*Multi Mailer implemented*/
@ -242,6 +243,21 @@ class NinjaMailerJob implements ShouldQueue
} }
/**
* Post mark buries the proper message in a guzzle response
* this merges a text string with a json object
* need to harvest the ->Message property using the following
*/
if ($e instanceof PostmarkException) { //postmark specific failure
$this->fail();
$this->entityEmailFailed($e->getMessage());
$this->cleanUpMailers();
return;
}
//only report once, not on all tries //only report once, not on all tries
if ($this->attempts() == $this->tries) { if ($this->attempts() == $this->tries) {
/* If there is an entity attached to the message send a failure mailer */ /* If there is an entity attached to the message send a failure mailer */
@ -249,10 +265,8 @@ class NinjaMailerJob implements ShouldQueue
$this->entityEmailFailed($message); $this->entityEmailFailed($message);
} }
/* Don't send postmark failures to Sentry */ app('sentry')->captureException($e);
if (Ninja::isHosted() && (!$e instanceof ClientException)) {
app('sentry')->captureException($e);
}
} }
/* Releasing immediately does not add in the backoff */ /* Releasing immediately does not add in the backoff */

View File

@ -57,13 +57,13 @@ class TaskScheduler implements ShouldQueue
->cursor() ->cursor()
->each(function ($scheduler) { ->each(function ($scheduler) {
nlog("Doing job {$scheduler->name}"); nlog("Doing job ::{$scheduler->id}:: {$scheduler->name}");
try { try {
//@var \App\Models\Schedule $scheduler //@var \App\Models\Schedule $scheduler
$scheduler->service()->runTask(); $scheduler->service()->runTask();
} catch(\Exception $e) { } catch(\Exception $e) {
nlog("Exception:: TaskScheduler:: Doing job {$scheduler->name}" . $e->getMessage()); nlog("Exception:: TaskScheduler:: Doing job :: {$scheduler->id} :: {$scheduler->name}" . $e->getMessage());
} }
}); });
@ -83,13 +83,13 @@ class TaskScheduler implements ShouldQueue
->cursor() ->cursor()
->each(function ($scheduler) { ->each(function ($scheduler) {
nlog("Doing job {$scheduler->name}"); nlog("Doing job ::{$scheduler->id}:: {$scheduler->name}");
try { try {
/** @var \App\Models\Scheduler $scheduler */ /** @var \App\Models\Scheduler $scheduler */
$scheduler->service()->runTask(); $scheduler->service()->runTask();
} catch(\Exception $e) { } catch(\Exception $e) {
nlog("Exception:: TaskScheduler::" . $e->getMessage()); nlog("Exception:: TaskScheduler:: #{$scheduler->id}::" . $e->getMessage());
nlog($e->getMessage()); nlog($e->getMessage());
} }

View File

@ -68,6 +68,8 @@ class ProcessPostmarkWebhook implements ShouldQueue
return SystemLog::query() return SystemLog::query()
->where('company_id', $this->invitation->company_id) ->where('company_id', $this->invitation->company_id)
->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE) ->where('type_id', SystemLog::TYPE_WEBHOOK_RESPONSE)
->where('category_id', SystemLog::CATEGORY_MAIL)
// ->where('client_id', $this->invitation->contact->client_id)
->whereJsonContains('log', ['MessageID' => $message_id]) ->whereJsonContains('log', ['MessageID' => $message_id])
->orderBy('id', 'desc') ->orderBy('id', 'desc')
->first(); ->first();

View File

@ -50,8 +50,6 @@ class SendRecurring implements ShouldQueue
*/ */
public function __construct(public RecurringInvoice $recurring_invoice, public string $db = 'db-ninja-01') public function __construct(public RecurringInvoice $recurring_invoice, public string $db = 'db-ninja-01')
{ {
$this->recurring_invoice = $recurring_invoice;
$this->db = $db;
} }
/** /**

View File

@ -71,7 +71,7 @@ class ReminderJob implements ShouldQueue
->whereHas('company', function ($query) { ->whereHas('company', function ($query) {
$query->where('is_disabled', 0); $query->where('is_disabled', 0);
}) })
->with('invitations')->chunk(200, function ($invoices) { ->with('invitations')->chunk(800, function ($invoices) {
foreach ($invoices as $invoice) { foreach ($invoices as $invoice) {
$this->sendReminderForInvoice($invoice); $this->sendReminderForInvoice($invoice);
} }
@ -99,7 +99,7 @@ class ReminderJob implements ShouldQueue
->whereHas('company', function ($query) { ->whereHas('company', function ($query) {
$query->where('is_disabled', 0); $query->where('is_disabled', 0);
}) })
->with('invitations')->chunk(200, function ($invoices) { ->with('invitations')->chunk(800, function ($invoices) {
foreach ($invoices as $invoice) { foreach ($invoices as $invoice) {
$this->sendReminderForInvoice($invoice); $this->sendReminderForInvoice($invoice);

View File

@ -297,7 +297,7 @@ class ClientContact extends Authenticatable implements HasLocalePreference
return $languages->first(function ($item) { return $languages->first(function ($item) {
return $item->id == $this->client->getSetting('language_id'); return $item->id == $this->client->getSetting('language_id');
})->locale; })->locale ?? 'en';
} }
public function routeNotificationForMail($notification) public function routeNotificationForMail($notification)

View File

@ -368,7 +368,7 @@ class Invoice extends BaseModel
public function activities() public function activities()
{ {
return $this->hasMany(Activity::class)->orderBy('id', 'DESC')->take(50); return $this->hasMany(Activity::class)->where('company_id', $this->company_id)->where('client_id', $this->client_id)->orderBy('id', 'DESC')->take(50);
} }
/** /**

View File

@ -189,7 +189,7 @@ class VendorContact extends Authenticatable implements HasLocalePreference
return $languages->first(function ($item) { return $languages->first(function ($item) {
return $item->id == $this->company->getSetting('language_id'); return $item->id == $this->company->getSetting('language_id');
})->locale; })->locale ?? 'en';
} }
/** /**

View File

@ -218,8 +218,27 @@ class CreditCard implements LivewireMethodInterface
{ {
$this->powerboard->init(); $this->powerboard->init();
// if(!isset($this->cba_gateway->verification_status) || $this->cba_gateway->verification_status != "completed") $available_cards = [
// throw new PaymentFailed("This payment method is not configured as yet. Reference Powerboard portal for further information", 400); "amex",
"ausbc",
"discover",
"japcb",
"laser",
"mastercard",
"solo",
"visa",
"visa_white",
];
$supported_cards = $this->powerboard->company_gateway->getConfig();
$supported_cards_array = [];
foreach($available_cards as $card){
if($supported_cards->{$card}){
$supported_cards_array[] = $card;
}
}
$merge = [ $merge = [
'public_key' => $this->powerboard->company_gateway->getConfigField('publicKey'), 'public_key' => $this->powerboard->company_gateway->getConfigField('publicKey'),
@ -227,6 +246,7 @@ class CreditCard implements LivewireMethodInterface
'gateway' => $this->powerboard, 'gateway' => $this->powerboard,
'environment' => $this->powerboard->environment, 'environment' => $this->powerboard->environment,
'gateway_id' => $this->cba_gateway->_id ?? false, 'gateway_id' => $this->cba_gateway->_id ?? false,
'supported_cards' => $supported_cards_array,
]; ];
return array_merge($data, $merge); return array_merge($data, $merge);

View File

@ -176,6 +176,19 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
*/ */
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $payment, string $status = 'paid'): RedirectResponse public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $payment, string $status = 'paid'): RedirectResponse
{ {
$p = \App\Models\Payment::query()
->withTrashed()
->where('company_id', $this->mollie->client->company_id)
->where('transaction_reference', $payment->id)
->first();
if($p) {
$p->status_id = Payment::STATUS_COMPLETED;
$p->save();
return redirect()->route('client.payments.show', ['payment' => $p->hashed_id]);
}
$data = [ $data = [
'gateway_type_id' => GatewayType::IDEAL, 'gateway_type_id' => GatewayType::IDEAL,
'amount' => array_sum(array_column($this->mollie->payment_hash->invoices(), 'amount')) + $this->mollie->payment_hash->fee_total, 'amount' => array_sum(array_column($this->mollie->payment_hash->invoices(), 'amount')) + $this->mollie->payment_hash->fee_total,

View File

@ -287,7 +287,7 @@ class MolliePaymentDriver extends BaseDriver
{ {
// Allow app to catch up with webhook request. // Allow app to catch up with webhook request.
// sleep(4); // sleep(4);
usleep(rand(2800000, 4000000)); usleep(rand(1500000, 4000000));
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'id' => ['required', 'starts_with:tr'], 'id' => ['required', 'starts_with:tr'],

View File

@ -11,38 +11,39 @@
namespace App\Services\Email; namespace App\Services\Email;
use App\DataMapper\Analytics\EmailFailure; use Log;
use App\DataMapper\Analytics\EmailSuccess; use App\Models\User;
use App\Events\Invoice\InvoiceWasEmailedAndFailed; use App\Utils\Ninja;
use App\Events\Payment\PaymentWasEmailedAndFailed;
use App\Jobs\Util\SystemLogger;
use App\Libraries\Google\Google;
use App\Libraries\MultiDB;
use App\Mail\Engine\PaymentEmailEngine;
use App\Models\Client; use App\Models\Client;
use App\Models\ClientContact; use App\Models\Vendor;
use App\Models\Company; use App\Models\Company;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
use App\Models\SystemLog; use App\Models\SystemLog;
use App\Models\User;
use App\Models\Vendor;
use App\Models\VendorContact;
use App\Utils\HtmlEngine; use App\Utils\HtmlEngine;
use App\Utils\Ninja; use App\Libraries\MultiDB;
use App\Models\ClientContact;
use App\Models\VendorContact;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use App\Jobs\Util\SystemLogger;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Utils\VendorHtmlEngine; use App\Utils\VendorHtmlEngine;
use App\Libraries\Google\Google;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Cache;
use Illuminate\Queue\SerializesModels;
use Postmark\Models\PostmarkException;
use Turbo124\Beacon\Facades\LightLogs;
use App\Mail\Engine\PaymentEmailEngine;
use Illuminate\Queue\InteractsWithQueue;
use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\ClientException;
use Illuminate\Bus\Queueable; use App\DataMapper\Analytics\EmailFailure;
use App\DataMapper\Analytics\EmailSuccess;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Mail\Mailable; use App\Events\Invoice\InvoiceWasEmailedAndFailed;
use Illuminate\Queue\InteractsWithQueue; use App\Events\Payment\PaymentWasEmailedAndFailed;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Mail;
use Log;
use Turbo124\Beacon\Facades\LightLogs;
class Email implements ShouldQueue class Email implements ShouldQueue
{ {
@ -375,16 +376,10 @@ class Email implements ShouldQueue
* this merges a text string with a json object * this merges a text string with a json object
* need to harvest the ->Message property using the following * need to harvest the ->Message property using the following
*/ */
if ($e instanceof ClientException) { //postmark specific failure if ($e instanceof PostmarkException) { //postmark specific failure
$response = $e->getResponse();
$message_body = json_decode($response->getBody()->getContents());
if ($message_body && property_exists($message_body, 'Message')) {
$message = $message_body->Message;
}
$this->fail(); $this->fail();
$this->entityEmailFailed($message); $this->entityEmailFailed($e->getMessage());
$this->cleanUpMailers(); $this->cleanUpMailers();
return; return;
@ -395,10 +390,8 @@ class Email implements ShouldQueue
/* If the is an entity attached to the message send a failure mailer */ /* If the is an entity attached to the message send a failure mailer */
$this->entityEmailFailed($message); $this->entityEmailFailed($message);
/* Don't send postmark failures to Sentry */ app('sentry')->captureException($e);
if (Ninja::isHosted() && (!$e instanceof ClientException)) {
app('sentry')->captureException($e);
}
} }
$this->tearDown(); $this->tearDown();
@ -985,7 +978,7 @@ class Email implements ShouldQueue
* @param string $message * @param string $message
* @return void * @return void
*/ */
private function entityEmailFailed($message): void private function entityEmailFailed(string $message = ''): void
{ {
$class = get_class($this->email_object->entity); $class = get_class($this->email_object->entity);

View File

@ -173,6 +173,11 @@ class QuickbooksService
return $this->sdk->FindById($entity, $id); return $this->sdk->FindById($entity, $id);
} }
public function query(string $query)
{
return $this->sdk->Query($query);
}
/** /**
* Flag to determine if a sync is allowed in either direction * Flag to determine if a sync is allowed in either direction
* *

38
composer.lock generated
View File

@ -2854,16 +2854,16 @@
}, },
{ {
"name": "google/apiclient-services", "name": "google/apiclient-services",
"version": "v0.373.0", "version": "v0.374.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/googleapis/google-api-php-client-services.git", "url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "88ee17077a2048ba0b2c637754b599be0523fe36" "reference": "5f6060df419f4f72dcc970197f9a9b1613cecc62"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/88ee17077a2048ba0b2c637754b599be0523fe36", "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/5f6060df419f4f72dcc970197f9a9b1613cecc62",
"reference": "88ee17077a2048ba0b2c637754b599be0523fe36", "reference": "5f6060df419f4f72dcc970197f9a9b1613cecc62",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2892,9 +2892,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/googleapis/google-api-php-client-services/issues", "issues": "https://github.com/googleapis/google-api-php-client-services/issues",
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.373.0" "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.374.0"
}, },
"time": "2024-09-16T00:56:51+00:00" "time": "2024-09-23T01:02:23+00:00"
}, },
{ {
"name": "google/auth", "name": "google/auth",
@ -7874,20 +7874,22 @@
}, },
{ {
"name": "nwidart/laravel-modules", "name": "nwidart/laravel-modules",
"version": "v11.1.2", "version": "v11.1.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nWidart/laravel-modules.git", "url": "https://github.com/nWidart/laravel-modules.git",
"reference": "d275a5b9f7c329c505480750d354a7eef69fc42a" "reference": "fb1f6bd7b168baaa6212dee678c18fc983d47ed4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nWidart/laravel-modules/zipball/d275a5b9f7c329c505480750d354a7eef69fc42a", "url": "https://api.github.com/repos/nWidart/laravel-modules/zipball/fb1f6bd7b168baaa6212dee678c18fc983d47ed4",
"reference": "d275a5b9f7c329c505480750d354a7eef69fc42a", "reference": "fb1f6bd7b168baaa6212dee678c18fc983d47ed4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*",
"ext-json": "*", "ext-json": "*",
"ext-simplexml": "*",
"php": ">=8.2", "php": ">=8.2",
"wikimedia/composer-merge-plugin": "^2.1" "wikimedia/composer-merge-plugin": "^2.1"
}, },
@ -7945,7 +7947,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/nWidart/laravel-modules/issues", "issues": "https://github.com/nWidart/laravel-modules/issues",
"source": "https://github.com/nWidart/laravel-modules/tree/v11.1.2" "source": "https://github.com/nWidart/laravel-modules/tree/v11.1.4"
}, },
"funding": [ "funding": [
{ {
@ -7957,7 +7959,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-09-20T08:45:18+00:00" "time": "2024-09-22T20:04:49+00:00"
}, },
{ {
"name": "nyholm/psr7", "name": "nyholm/psr7",
@ -9362,16 +9364,16 @@
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "1.30.1", "version": "1.31.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "51b95ec8670af41009e2b2b56873bad96682413e" "reference": "249f15fb843bf240cf058372dad29e100cee6c17"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/51b95ec8670af41009e2b2b56873bad96682413e", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/249f15fb843bf240cf058372dad29e100cee6c17",
"reference": "51b95ec8670af41009e2b2b56873bad96682413e", "reference": "249f15fb843bf240cf058372dad29e100cee6c17",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -9403,9 +9405,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.1" "source": "https://github.com/phpstan/phpdoc-parser/tree/1.31.0"
}, },
"time": "2024-09-07T20:13:05+00:00" "time": "2024-09-22T11:32:18+00:00"
}, },
{ {
"name": "pragmarx/google2fa", "name": "pragmarx/google2fa",

View File

@ -22,6 +22,16 @@ return new class extends Migration
$fields->secretKey = ''; $fields->secretKey = '';
$fields->testMode = false; $fields->testMode = false;
$fields->gatewayId = ''; $fields->gatewayId = '';
$fields->amex = false;
$fields->ausbc = false;
$fields->discover = false;
$fields->japcb = false;
$fields->laser = false;
$fields->mastercard = true;
$fields->solo = false;
$fields->visa = true;
$fields->visa_white = false;
if($gateway = Gateway::find(64)){ if($gateway = Gateway::find(64)){
$gateway->fields = json_encode($fields); $gateway->fields = json_encode($fields);

View File

@ -89,7 +89,7 @@ class PaymentLibrariesSeeder extends Seeder
['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'], ['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'],
['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], ['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'],
['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":false}'], ['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":false}'],
['id' => 64, 'name' => 'CBA PowerBoard', 'is_offsite' => false, 'sort_order' => 26, 'provider' => 'CBAPowerBoard', 'key' => 'b67581d804dbad1743b61c57285142ad', 'fields' => '{"publicKey":"", "secretKey":"", "testMode":false, "gatewayId":""}'], ['id' => 64, 'name' => 'CBA PowerBoard', 'is_offsite' => false, 'sort_order' => 26, 'provider' => 'CBAPowerBoard', 'key' => 'b67581d804dbad1743b61c57285142ad', 'fields' => '{"publicKey":"", "secretKey":"", "testMode":false, "gatewayId":"", "amex":false, "ausbc":false, "discover":false, "japcb":false, "laser":false, "mastercard":true, "solo":false, "visa":true, "visa_white":false}'],
['id' => 65, 'name' => 'Blockonomics', 'is_offsite' => false, 'sort_order' => 27, 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => '{"apiKey":"", "callbackSecret":""}'], ['id' => 65, 'name' => 'Blockonomics', 'is_offsite' => false, 'sort_order' => 27, 'provider' => 'Blockonomics', 'key' => 'wbhf02us6owgo7p4nfjd0ymssdshks4d', 'fields' => '{"apiKey":"", "callbackSecret":""}'],
]; ];

View File

@ -0,0 +1,13 @@
import{i as l,w as m}from"./wait-8f4ae121.js";/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/let u=!1;function y(){const t=document.querySelector("meta[name=public_key]"),e=document.querySelector("meta[name=gateway_id]"),r=document.querySelector("meta[name=environment]"),n=document.querySelector("meta[name=supported_cards]"),o=new cba.HtmlWidget("#widget",t==null?void 0:t.content,e==null?void 0:e.content);if(o.setEnv(r==null?void 0:r.content),o.useAutoResize(),n!=null&&n.content)try{const a=JSON.parse(n.content);o.setSupportedCardIcons(a,!0)}catch{}o.interceptSubmitForm("#stepone"),o.onFinishInsert('#server-response input[name="gateway_response"]',"payment_source"),o.setFormFields(["card_name*"]),o.reload();let d=document.getElementById("pay-now");return d.disabled=!1,d.querySelector("svg").classList.add("hidden"),d.querySelector("span").classList.remove("hidden"),document.querySelector('#server-response input[name="gateway_response"]').value="",o}function g(){var t,e,r;(t=document.querySelector("#widget"))==null||t.replaceChildren(),(e=document.querySelector("#widget"))==null||e.classList.remove("hidden"),(r=document.querySelector("#widget-3dsecure"))==null||r.replaceChildren()}function s(){var o,d;if(g(),!((o=document.querySelector("meta[name=gateway_id]"))==null?void 0:o.content)){let a=document.getElementById("pay-now");a.disabled=!0,a.querySelector("svg").classList.remove("hidden"),a.querySelector("span").classList.add("hidden"),document.getElementById("errors").textContent="Gateway not found or verified",document.getElementById("errors").hidden=!1}const e=y();e.on("finish",()=>{document.getElementById("errors").hidden=!0,p()}),e.on("submit",function(a){document.getElementById("errors").hidden=!0});let r=document.getElementById("pay-now");r.addEventListener("click",()=>{const a=document.getElementById("widget");if(e.getValidationState(),!e.isValidForm()&&a.offsetParent!==null){r.disabled=!1,r.querySelector("svg").classList.add("hidden"),r.querySelector("span").classList.remove("hidden");return}r.disabled=!0,r.querySelector("svg").classList.remove("hidden"),r.querySelector("span").classList.add("hidden");let c=document.querySelector("input[name=token-billing-checkbox]:checked");c&&(document.getElementById("store_card").value=c.value),a.offsetParent!==null?document.getElementById("stepone_submit").click():document.getElementById("server-response").submit()}),document.getElementById("toggle-payment-with-credit-card").addEventListener("click",a=>{var i;document.getElementById("widget").classList.remove("hidden"),document.getElementById("save-card--container").style.display="grid",document.querySelector("input[name=token]").value="",(i=document.querySelector("#powerboard-payment-container"))==null||i.classList.remove("hidden")}),Array.from(document.getElementsByClassName("toggle-payment-with-token")).forEach(a=>a.addEventListener("click",c=>{var i;document.getElementById("widget").classList.add("hidden"),document.getElementById("save-card--container").style.display="none",document.querySelector("input[name=token]").value=c.target.dataset.token,(i=document.querySelector("#powerboard-payment-container"))==null||i.classList.add("hidden")}));const n=document.querySelector('input[name="payment-type"]');n&&n.click(),u&&((d=document.getElementById("toggle-payment-with-credit-card"))==null||d.click())}async function p(){try{const t=await h();if(!t||!t.status||t.status==="not_authenticated"||t==="not_authenticated")throw u=!0,s(),new Error("There was an issue authenticating this payment method.");if(t.status==="authentication_not_supported"){document.querySelector('input[name="browser_details"]').value=null,document.querySelector('input[name="charge"]').value=JSON.stringify(t);let n=document.querySelector("input[name=token-billing-checkbox]:checked");return n&&(document.getElementById("store_card").value=n.value),document.getElementById("server-response").submit()}const e=new cba.Canvas3ds("#widget-3dsecure",t._3ds.token);e.load(),document.getElementById("widget").classList.add("hidden"),e.on("chargeAuthSuccess",function(n){document.querySelector('input[name="browser_details"]').value=null,document.querySelector('input[name="charge"]').value=JSON.stringify(n);let o=document.querySelector("input[name=token-billing-checkbox]:checked");o&&(document.getElementById("store_card").value=o.value),document.getElementById("server-response").submit()}),e.on("chargeAuthReject",function(n){document.getElementById("errors").textContent="Sorry, your transaction could not be processed...",document.getElementById("errors").hidden=!1,u=!0,s()}),e.load()}catch(t){const e=t.message??"Unknown error.";document.getElementById("errors").textContent=`Sorry, your transaction could not be processed...
${e}`,document.getElementById("errors").hidden=!1,u=!0,s()}}async function h(){const t={name:navigator.userAgent.substring(0,100),java_enabled:navigator.javaEnabled()?"true":"false",language:navigator.language||navigator.userLanguage,screen_height:window.screen.height.toString(),screen_width:window.screen.width.toString(),time_zone:(new Date().getTimezoneOffset()*-1).toString(),color_depth:window.screen.colorDepth.toString()};document.querySelector('input[name="browser_details"]').value=JSON.stringify(t);const e=JSON.stringify(Object.fromEntries(new FormData(document.getElementById("server-response")))),r=document.querySelector("meta[name=payments_route]");try{const n=await fetch(r.content,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest",Accept:"application/json","X-CSRF-Token":document.querySelector('meta[name="csrf-token"]').content},body:e});return n.ok?await n.json():await n.json().then(o=>{throw new Error(o.message??"Unknown error.")})}catch(n){document.getElementById("errors").textContent=`Sorry, your transaction could not be processed...
${n.message}`,document.getElementById("errors").hidden=!1,u=!0,s()}}l()?s():m("#powerboard-credit-card-payment").then(()=>s());

View File

@ -1,13 +0,0 @@
import{i as l,w as m}from"./wait-8f4ae121.js";/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/let i=!1;function y(){const n=document.querySelector("meta[name=public_key]"),t=document.querySelector("meta[name=gateway_id]"),r=document.querySelector("meta[name=environment]"),e=new cba.HtmlWidget("#widget",n==null?void 0:n.content,t==null?void 0:t.content);e.setEnv(r==null?void 0:r.content),e.useAutoResize(),e.interceptSubmitForm("#stepone"),e.onFinishInsert('#server-response input[name="gateway_response"]',"payment_source"),e.setFormFields(["card_name*"]),e.reload();let o=document.getElementById("pay-now");return o.disabled=!1,o.querySelector("svg").classList.add("hidden"),o.querySelector("span").classList.remove("hidden"),document.querySelector('#server-response input[name="gateway_response"]').value="",e}function g(){var n,t,r;(n=document.querySelector("#widget"))==null||n.replaceChildren(),(t=document.querySelector("#widget"))==null||t.classList.remove("hidden"),(r=document.querySelector("#widget-3dsecure"))==null||r.replaceChildren()}function a(){var o,u;if(g(),!((o=document.querySelector("meta[name=gateway_id]"))==null?void 0:o.content)){let d=document.getElementById("pay-now");d.disabled=!0,d.querySelector("svg").classList.remove("hidden"),d.querySelector("span").classList.add("hidden"),document.getElementById("errors").textContent="Gateway not found or verified",document.getElementById("errors").hidden=!1}const t=y();t.on("finish",()=>{document.getElementById("errors").hidden=!0,p()}),t.on("submit",function(d){document.getElementById("errors").hidden=!0});let r=document.getElementById("pay-now");r.addEventListener("click",()=>{const d=document.getElementById("widget");if(t.getValidationState(),!t.isValidForm()&&d.offsetParent!==null){r.disabled=!1,r.querySelector("svg").classList.add("hidden"),r.querySelector("span").classList.remove("hidden");return}r.disabled=!0,r.querySelector("svg").classList.remove("hidden"),r.querySelector("span").classList.add("hidden");let s=document.querySelector("input[name=token-billing-checkbox]:checked");s&&(document.getElementById("store_card").value=s.value),d.offsetParent!==null?document.getElementById("stepone_submit").click():document.getElementById("server-response").submit()}),document.getElementById("toggle-payment-with-credit-card").addEventListener("click",d=>{var c;document.getElementById("widget").classList.remove("hidden"),document.getElementById("save-card--container").style.display="grid",document.querySelector("input[name=token]").value="",(c=document.querySelector("#powerboard-payment-container"))==null||c.classList.remove("hidden")}),Array.from(document.getElementsByClassName("toggle-payment-with-token")).forEach(d=>d.addEventListener("click",s=>{var c;document.getElementById("widget").classList.add("hidden"),document.getElementById("save-card--container").style.display="none",document.querySelector("input[name=token]").value=s.target.dataset.token,(c=document.querySelector("#powerboard-payment-container"))==null||c.classList.add("hidden")}));const e=document.querySelector('input[name="payment-type"]');e&&e.click(),i&&((u=document.getElementById("toggle-payment-with-credit-card"))==null||u.click())}async function p(){try{const n=await h();if(!n||!n.status||n.status==="not_authenticated"||n==="not_authenticated")throw i=!0,a(),new Error("There was an issue authenticating this payment method.");if(n.status==="authentication_not_supported"){document.querySelector('input[name="browser_details"]').value=null,document.querySelector('input[name="charge"]').value=JSON.stringify(n);let e=document.querySelector("input[name=token-billing-checkbox]:checked");return e&&(document.getElementById("store_card").value=e.value),document.getElementById("server-response").submit()}const t=new cba.Canvas3ds("#widget-3dsecure",n._3ds.token);t.load(),document.getElementById("widget").classList.add("hidden"),t.on("chargeAuthSuccess",function(e){document.querySelector('input[name="browser_details"]').value=null,document.querySelector('input[name="charge"]').value=JSON.stringify(e);let o=document.querySelector("input[name=token-billing-checkbox]:checked");o&&(document.getElementById("store_card").value=o.value),document.getElementById("server-response").submit()}),t.on("chargeAuthReject",function(e){document.getElementById("errors").textContent="Sorry, your transaction could not be processed...",document.getElementById("errors").hidden=!1,i=!0,a()}),t.load()}catch(n){const t=n.message??"Unknown error.";document.getElementById("errors").textContent=`Sorry, your transaction could not be processed...
${t}`,document.getElementById("errors").hidden=!1,i=!0,a()}}async function h(){const n={name:navigator.userAgent.substring(0,100),java_enabled:navigator.javaEnabled()?"true":"false",language:navigator.language||navigator.userLanguage,screen_height:window.screen.height.toString(),screen_width:window.screen.width.toString(),time_zone:(new Date().getTimezoneOffset()*-1).toString(),color_depth:window.screen.colorDepth.toString()};document.querySelector('input[name="browser_details"]').value=JSON.stringify(n);const t=JSON.stringify(Object.fromEntries(new FormData(document.getElementById("server-response")))),r=document.querySelector("meta[name=payments_route]");try{const e=await fetch(r.content,{method:"POST",headers:{"Content-Type":"application/json","X-Requested-With":"XMLHttpRequest",Accept:"application/json","X-CSRF-Token":document.querySelector('meta[name="csrf-token"]').content},body:t});return e.ok?await e.json():await e.json().then(o=>{throw new Error(o.message??"Unknown error.")})}catch(e){document.getElementById("errors").textContent=`Sorry, your transaction could not be processed...
${e.message}`,document.getElementById("errors").hidden=!1,i=!0,a()}}l()?a():m("#powerboard-credit-card-payment").then(()=>a());

View File

@ -158,7 +158,7 @@
"src": "resources/js/clients/payments/paytrace-credit-card.js" "src": "resources/js/clients/payments/paytrace-credit-card.js"
}, },
"resources/js/clients/payments/powerboard-credit-card.js": { "resources/js/clients/payments/powerboard-credit-card.js": {
"file": "assets/powerboard-credit-card-f5f23291.js", "file": "assets/powerboard-credit-card-f4852d3b.js",
"imports": [ "imports": [
"_wait-8f4ae121.js" "_wait-8f4ae121.js"
], ],

View File

@ -16,6 +16,7 @@ function setup() {
const publicKey = document.querySelector('meta[name=public_key]'); const publicKey = document.querySelector('meta[name=public_key]');
const gatewayId = document.querySelector('meta[name=gateway_id]'); const gatewayId = document.querySelector('meta[name=gateway_id]');
const env = document.querySelector('meta[name=environment]'); const env = document.querySelector('meta[name=environment]');
const supportedCards = document.querySelector('meta[name=supported_cards]');
const widget = new cba.HtmlWidget( const widget = new cba.HtmlWidget(
'#widget', '#widget',
@ -25,6 +26,15 @@ function setup() {
widget.setEnv(env?.content); widget.setEnv(env?.content);
widget.useAutoResize(); widget.useAutoResize();
if (supportedCards?.content) {
try {
const supportedCardsArray = JSON.parse(supportedCards.content);
widget.setSupportedCardIcons(supportedCardsArray, true);
} catch (error) {
}
}
widget.interceptSubmitForm('#stepone'); widget.interceptSubmitForm('#stepone');
widget.onFinishInsert( widget.onFinishInsert(
'#server-response input[name="gateway_response"]', '#server-response input[name="gateway_response"]',

View File

@ -6,6 +6,7 @@
<meta name="gateway_id" content="{{ $gateway_id }}" /> <meta name="gateway_id" content="{{ $gateway_id }}" />
<meta name="environment" content="{{ $environment }}"> <meta name="environment" content="{{ $environment }}">
<meta name="payments_route" content="{{ route('client.payments.response') }}" /> <meta name="payments_route" content="{{ route('client.payments.response') }}" />
<meta name="supported_cards" content="{{ json_encode($supported_cards) }}" />
@endsection @endsection
@section('gateway_content') @section('gateway_content')

View File

@ -4,6 +4,7 @@
<meta name="gateway_id" content="{{ $gateway_id }}" /> <meta name="gateway_id" content="{{ $gateway_id }}" />
<meta name="environment" content="{{ $environment }}"> <meta name="environment" content="{{ $environment }}">
<meta name="payments_route" content="{{ route('client.payments.response') }}" /> <meta name="payments_route" content="{{ route('client.payments.response') }}" />
<meta name="supported_cards" content="{{ json_encode($supported_cards) }}" />
<form action="javascript:void(0);" id="stepone"> <form action="javascript:void(0);" id="stepone">
<input type="hidden" name="gateway_response"> <input type="hidden" name="gateway_response">

View File

@ -52,13 +52,15 @@ class QuickbooksTest extends TestCase
$this->faker = \Faker\Factory::create(); $this->faker = \Faker\Factory::create();
} }
public function createQbProduct() public function createQbProduct()
{ {
$service_product = Product::factory()->create([ $service_product = Product::factory()->create([
'company_id' => $this->company->id, 'company_id' => $this->company->id,
'user_id' => $this->company->owner()->id, 'user_id' => $this->company->owner()->id,
'notes' => $this->faker->sentence(), 'notes' => $this->faker->sentence(),
'product_key' => $this->faker->word(63), 'product_key' => \Illuminate\Support\Str::random(64),
'tax_id' => 2, 'tax_id' => 2,
]); ]);
@ -67,7 +69,7 @@ class QuickbooksTest extends TestCase
'company_id' => $this->company->id, 'company_id' => $this->company->id,
'user_id' => $this->company->owner()->id, 'user_id' => $this->company->owner()->id,
'notes' => $this->faker->sentence(), 'notes' => $this->faker->sentence(),
'product_key' => $this->faker->word(63), 'product_key' => \Illuminate\Support\Str::random(64),
'tax_id' => 1, 'tax_id' => 1,
]); ]);
@ -135,11 +137,17 @@ class QuickbooksTest extends TestCase
$client = Client::factory()->create([ $client = Client::factory()->create([
'company_id' => $this->company->id, 'company_id' => $this->company->id,
'user_id' => $this->company->owner()->id, 'user_id' => $this->company->owner()->id,
'address1' => $this->faker->address(), 'address1' => "10369 Ashton Avenue",
'city' => $this->faker->city(), 'address2' => '',
'state' => $this->faker->state(), 'city' => "Beverley Hills",
'postal_code' => $this->faker->postcode(), 'state' => "California",
'postal_code' => "90210",
'country_id' => 840, 'country_id' => 840,
'shipping_address1' => "10369 Ashton Avenue",
'address2' => '',
'shipping_city' => "Beverley Hills",
'shipping_state' => "California",
'shipping_postal_code' => "90210",
'shipping_country_id' => 840, 'shipping_country_id' => 840,
]); ]);
@ -213,9 +221,16 @@ class QuickbooksTest extends TestCase
//create ninja invoice //create ninja invoice
$qb_invoice = $this->createQbInvoice($customer); $qb_invoice = $this->createQbInvoice($customer);
$this->assertNotNull($qb_invoice);
nlog($qb_invoice); $this->assertNotNull($qb_invoice);
// sleep(5);
// $updatedInvoice = $this->qb->sdk->FindById('invoice', $qb_invoice->Id->value);
nlog($updatedInvoice);
} }
public function testCreateCustomerInQb() public function testCreateCustomerInQb()
@ -262,6 +277,8 @@ class QuickbooksTest extends TestCase
$item_product->quantity = 1; $item_product->quantity = 1;
$item_product->cost = $non_inventory_product->price; $item_product->cost = $non_inventory_product->price;
$item_product->line_total = $non_inventory_product->price; $item_product->line_total = $non_inventory_product->price;
$item_product->tax_name1 = 'CA Sales Tax';
$item_product->tax_rate1 = 8;
$item_product->type_id = '1'; $item_product->type_id = '1';
$item_service = new InvoiceItem(); $item_service = new InvoiceItem();
@ -303,6 +320,12 @@ class QuickbooksTest extends TestCase
// $this->assertEquals(30, $i->balance); // $this->assertEquals(30, $i->balance);
$line_items = []; $line_items = [];
// $taxDetail = [
// "TotalTax" => 0,
// "TaxLine" => []
// ];
$line_num = 1; $line_num = 1;
foreach($i->line_items as $line_item) foreach($i->line_items as $line_item)
@ -327,10 +350,68 @@ class QuickbooksTest extends TestCase
], ],
], ],
'Description' => $line_item->notes, 'Description' => $line_item->notes,
'Amount' => $line_item->line_total, 'Amount' => $line_item->line_total,
]; ];
// if($line_item->tax_rate1 > 0)
// {
// $tax_line_detail = [
// "Amount" => $line_item->tax_amount,
// "DetailType" => "TaxLineDetail",
// "TaxLineDetail" => [
// "TaxRateRef" => [
// "value" => $line_item->tax_rate1,
// "name" => $line_item->tax_name1,
// ],
// "PercentBased" => true,
// "TaxPercent" => $line_item->tax_rate1,
// "NetAmountTaxable" => $line_item->line_total,
// ]
// ];
// $taxDetail['TaxLine'][] = $tax_line_detail;
// $taxDetail['TotalTax'] += $line_item->tax_amount;
// }
// if ($line_item->tax_rate2 > 0) {
// $tax_line_detail = [
// "Amount" => $line_item->tax_amount,
// "DetailType" => "TaxLineDetail",
// "TaxLineDetail" => [
// "TaxRateRef" => [
// "value" => $line_item->tax_rate2,
// "name" => $line_items->tax_name2,
// ],
// "PercentBased" => true,
// "TaxPercent" => $line_item->tax_rate2,
// "NetAmountTaxable" => $line_item->line_total,
// ]
// ];
// $taxDetail['TaxLine'][] = $tax_line_detail;
// $taxDetail['TotalTax'] += $line_item->tax_amount;
// }
// if ($line_item->tax_rate3 > 0) {
// $tax_line_detail = [
// "Amount" => $line_item->tax_amount,
// "DetailType" => "TaxLineDetail",
// "TaxLineDetail" => [
// "TaxRateRef" => [
// "value" => $line_item->tax_name3
// ],
// "PercentBased" => true,
// "TaxPercent" => $line_item->tax_rate3,
// "NetAmountTaxable" => $line_item->line_total,
// ]
// ];
// $taxDetail['TaxLine'][] = $tax_line_detail;
// $taxDetail['TotalTax'] += $line_item->tax_amount;
// }
$line_num++; $line_num++;
} }
@ -347,15 +428,19 @@ class QuickbooksTest extends TestCase
"DueDate" => $i->due_date, "DueDate" => $i->due_date,
"TotalAmt" => $i->amount, "TotalAmt" => $i->amount,
"DocNumber" => $i->number, "DocNumber" => $i->number,
"ApplyTaxAfterDiscount" => false, "ApplyTaxAfterDiscount" => true,
"GlobalTaxCalculation" => "TaxExcluded", // This tells QuickBooks to calculate taxes "PrintStatus" => "NeedToPrint",
"TxnTaxDetail" => [ "EmailStatus" => "NotSet",
"UseAutomatedSalesTax" => true, "GlobalTaxCalculation" => "TaxExcluded",
// "ApplyTaxAfterDiscount" => false,
// "TxnTaxDetail" => $taxDetail,
// "TxnTaxDetail" => [
// "UseAutomatedSalesTax" => true,
// "TxnTaxCodeRef" => [ // "TxnTaxCodeRef" => [
// "value" => "TAX" // Use the appropriate tax code for your QuickBooks account // "value" => "SALES_TAX_STUB" // Use the appropriate tax code for your QuickBooks account
// "DefaultTaxRateRef" => [ // "DefaultTaxRateRef" => [
// ] // ],
] // ]
// "Note" => $this->invoice->public_notes, // "Note" => $this->invoice->public_notes,
]; ];

View File

@ -62,6 +62,38 @@ class PaymentTest extends TestCase
); );
} }
public function testNullPaymentAmounts()
{
$data = [
'amount' => "null",
'client_id' => "null",
'invoices' => [
[
'invoice_id' => $this->invoice->hashed_id,
'amount' => "null",
],
],
'credits' => [
[
'credit_id' => $this->invoice->hashed_id,
'amount' => "null",
],
],
'date' => '2020/12/11',
'idempotency_key' => 'xx',
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/payments/', $data);
$response->assertStatus(422);
}
public function testIdempotencyTrigger() public function testIdempotencyTrigger()
{ {