1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 13:12:50 +01:00

Merge pull request #8840 from turbo124/v5-develop

v5.7.23
This commit is contained in:
David Bomba 2023-09-30 09:42:34 +10:00 committed by GitHub
commit 4f986df06c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 658 additions and 245 deletions

View File

@ -1 +1 @@
5.7.22
5.7.23

View File

@ -83,6 +83,7 @@ class BaseExport
'contact_custom_value4' => 'vendor_contact.custom_value4',
'email' => 'vendor_contact.email',
'status' => 'vendor.status',
'classification' => 'vendor.classification',
];
protected array $client_report_keys = [
@ -125,7 +126,9 @@ class BaseExport
"contact_custom_value2" => "contact.custom_value2",
"contact_custom_value3" => "contact.custom_value3",
"contact_custom_value4" => "contact.custom_value4",
'payment_balance' => 'client.payment_balance',
'credit_balance' => 'client.credit_balance',
'classification' => 'client.classification',
];
protected array $invoice_report_keys = [

View File

@ -71,7 +71,11 @@ class ClientExport extends BaseExport
'contact_custom_value3' => 'contact.custom_value3',
'contact_custom_value4' => 'contact.custom_value4',
'email' => 'contact.email',
'status' => 'status'
'status' => 'status',
'payment_balance' => 'client.payment_balance',
'credit_balance' => 'client.credit_balance',
'classification' => 'client.classification',
];
public function __construct(Company $company, array $input)
@ -223,6 +227,10 @@ class ClientExport extends BaseExport
$entity['industry_id'] = $client->industry ? ctrans("texts.industry_{$client->industry->name}") : '';
}
if (in_array('client.classification', $this->input['report_keys']) && isset($client->classification)) {
$entity['client.classification'] = ctrans("texts.{$client->classification}") ?? '';
}
return $entity;
}

View File

@ -139,7 +139,11 @@ class VendorExport extends BaseExport
$entity['currency'] = $vendor->currency() ? $vendor->currency()->code : $vendor->company->currency()->code;
}
$entity['status'] = $this->calculateStatus($vendor);
if (in_array('vendor.classification', $this->input['report_keys']) && isset($vendor->classification)) {
$entity['vendor.classification'] = ctrans("texts.{$vendor->classification}") ?? '';
}
// $entity['status'] = $this->calculateStatus($vendor);
return $entity;
}

View File

@ -123,11 +123,14 @@ class ClientController extends BaseController
return $request->disallowUpdate();
}
/** @var \App\Models\User $user */
$user = auth()->user();
$client = $this->client_repo->save($request->all(), $client);
$this->uploadLogo($request->file('company_logo'), $client->company, $client);
event(new ClientWasUpdated($client, $client->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
event(new ClientWasUpdated($client, $client->company, Ninja::eventVars($user ? $user->id : null)));
return $this->itemResponse($client->fresh());
}
@ -141,7 +144,10 @@ class ClientController extends BaseController
*/
public function create(CreateClientRequest $request)
{
$client = ClientFactory::create(auth()->user()->company()->id, auth()->user()->id);
/** @var \App\Models\User $user */
$user = auth()->user();
$client = ClientFactory::create($user->company()->id, $user->id);
return $this->itemResponse($client);
}
@ -155,7 +161,10 @@ class ClientController extends BaseController
*/
public function store(StoreClientRequest $request)
{
$client = $this->client_repo->save($request->all(), ClientFactory::create(auth()->user()->company()->id, auth()->user()->id));
/** @var \App\Models\User $user */
$user = auth()->user();
$client = $this->client_repo->save($request->all(), ClientFactory::create($user->company()->id, $user->id));
$client->load('contacts', 'primary_contact');
@ -166,7 +175,7 @@ class ClientController extends BaseController
$this->uploadLogo($request->file('company_logo'), $client->company, $client);
event(new ClientWasCreated($client, $client->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
event(new ClientWasCreated($client, $client->company, Ninja::eventVars(auth()->user() ? $user->id : null)));
return $this->itemResponse($client);
}
@ -273,9 +282,12 @@ class ClientController extends BaseController
public function merge(PurgeClientRequest $request, Client $client, string $mergeable_client)
{
/** @var \App\Models\User $user */
$user = auth()->user();
$m_client = Client::withTrashed()
->where('id', $this->decodePrimaryKey($mergeable_client))
->where('company_id', auth()->user()->company()->id)
->where('company_id', $user->company()->id)
->first();
if (!$m_client) {

View File

@ -73,7 +73,10 @@ class TaskStatusController extends BaseController
*/
public function create(CreateTaskStatusRequest $request)
{
$task_status = TaskStatusFactory::create(auth()->user()->company()->id, auth()->user()->id);
/** @var \App\Models\User $user */
$user = auth()->user();
$task_status = TaskStatusFactory::create($user->company()->id, auth()->user()->id);
return $this->itemResponse($task_status);
}
@ -87,8 +90,10 @@ class TaskStatusController extends BaseController
*/
public function store(StoreTaskStatusRequest $request)
{
/** @var \App\Models\User $user */
$user = auth()->user();
$task_status = TaskStatusFactory::create(auth()->user()->company()->id, auth()->user()->id);
$task_status = TaskStatusFactory::create($user->company()->id, auth()->user()->id);
$task_status->fill($request->all());
$task_status->save();

View File

@ -125,7 +125,10 @@ class TaxRateController extends BaseController
*/
public function create(CreateTaxRateRequest $request)
{
$tax_rate = TaxRateFactory::create(auth()->user()->company()->id, auth()->user()->id);
/** @var \App\Models\User $user */
$user = auth()->user();
$tax_rate = TaxRateFactory::create($user->company()->id, auth()->user()->id);
return $this->itemResponse($tax_rate);
}
@ -138,7 +141,10 @@ class TaxRateController extends BaseController
*/
public function store(StoreTaxRateRequest $request)
{
$tax_rate = TaxRateFactory::create(auth()->user()->company()->id, auth()->user()->id);
/** @var \App\Models\User $user */
$user = auth()->user();
$tax_rate = TaxRateFactory::create($user->company()->id, $user->id);
$tax_rate->fill($request->all());
$tax_rate->save();
@ -417,15 +423,33 @@ class TaxRateController extends BaseController
*/
public function bulk()
{
$action = request()->input('action');
/** @var \App\Models\User $user */
$user = auth()->user();
$action = request()->input('action');
$ids = request()->input('ids');
$tax_rates = TaxRate::withTrashed()->find($this->transformKeys($ids));
$tax_rates->each(function ($tax_rate, $key) use ($action) {
if (auth()->user()->can('edit', $tax_rate)) {
$tax_rates->each(function ($tax_rate, $key) use ($action, $user) {
if ($user->can('edit', $tax_rate)) {
if(in_array($action, ['archive','delete'])) {
$settings = $user->company()->settings;
foreach(['tax_name1','tax_name2','tax_name3'] as $tax_name) {
if($settings->{$tax_name} == $tax_rate->name) {
$settings->{$tax_name} = '';
$settings->{str_replace("name", "rate", $tax_name)} = '';
}
}
$user->company()->saveSettings($settings, $user->company());
}
$this->base_repo->{$action}($tax_rate);
}
});

View File

@ -93,7 +93,7 @@ class StoreClientRequest extends Request
$rules['number'] = ['bail', 'nullable', Rule::unique('clients')->where('company_id', $user->company()->id)];
$rules['id_number'] = ['bail', 'nullable', Rule::unique('clients')->where('company_id', $user->company()->id)];
$rules['classification'] = 'bail|sometimes|nullable|in:individual,company,partnership,trust,charity,government,other';
$rules['classification'] = 'bail|sometimes|nullable|in:individual,business,partnership,trust,charity,government,other';
return $rules;
}

View File

@ -60,7 +60,7 @@ class UpdateClientRequest extends Request
$rules['size_id'] = 'integer|nullable';
$rules['country_id'] = 'integer|nullable';
$rules['shipping_country_id'] = 'integer|nullable';
$rules['classification'] = 'bail|sometimes|nullable|in:individual,company,partnership,trust,charity,government,other';
$rules['classification'] = 'bail|sometimes|nullable|in:individual,business,partnership,trust,charity,government,other';
if ($this->id_number) {
$rules['id_number'] = Rule::unique('clients')->where('company_id', $user->company()->id)->ignore($this->client->id);

View File

@ -30,7 +30,10 @@ class StoreUserRequest extends Request
*/
public function authorize() : bool
{
return auth()->user()->isAdmin();
/** @var \App\Models\User $user */
$user = auth()->user();
return $user->isAdmin();
}
public function rules()

View File

@ -330,7 +330,7 @@ class BaseDriver extends AbstractPaymentDriver
$payment->gateway_type_id = $data['gateway_type_id'];
$client_contact = $this->getContact();
$client_contact_id = $client_contact ? $client_contact->id : null;
$client_contact_id = $client_contact ? $client_contact->id : $this->client->contacts()->first()->id;
$payment->amount = $data['amount'];
$payment->type_id = $data['payment_type'];
@ -430,9 +430,9 @@ class BaseDriver extends AbstractPaymentDriver
public function getContact()
{
if ($this->invitation) {
return ClientContact::find($this->invitation->client_contact_id);
return ClientContact::withTrashed()->find($this->invitation->client_contact_id);
} elseif (auth()->guard('contact')->user()) {
return auth()->user();
return auth()->guard('contact')->user();
} else {
return false;
}

View File

@ -121,21 +121,24 @@ class CheckoutComPaymentDriver extends BaseDriver
$this->is_four_api = true; //was four api, now known as previous.
/** @phpstan-ignore-next-line **/
$builder = CheckoutSdk::builder()
->previous()
->staticKeys()
->environment($this->company_gateway->getConfigField('testMode') ? Environment::sandbox() : Environment::production())
->environment($this->company_gateway->getConfigField('testMode') ? Environment::sandbox() : Environment::production()) /** phpstan-ignore-line **/
->publicKey($this->company_gateway->getConfigField('publicApiKey'))
->secretKey($this->company_gateway->getConfigField('secretApiKey'));
$this->gateway = $builder->build();
} else {
$builder = CheckoutSdk::builder()->staticKeys()
/** @phpstan-ignore-next-line **/
$builder = CheckoutSdk::builder()
->staticKeys()
->environment($this->company_gateway->getConfigField('testMode') ? Environment::sandbox() : Environment::production()) /** phpstan-ignore-line **/
->publicKey($this->company_gateway->getConfigField('publicApiKey'))
->secretKey($this->company_gateway->getConfigField('secretApiKey'))
->environment($this->company_gateway->getConfigField('testMode') ? Environment::sandbox() : Environment::production());
->secretKey($this->company_gateway->getConfigField('secretApiKey'));
$this->gateway = $builder->build();
@ -221,6 +224,16 @@ class CheckoutComPaymentDriver extends BaseDriver
$response = $this->gateway->getPaymentsClient()->refundPayment($payment->transaction_reference, $request);
SystemLogger::dispatch(
array_merge(['message' => "Gateway Refund"], $response),
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_CHECKOUT,
$payment->client,
$payment->company,
);
return [
'transaction_reference' => $response['action_id'],
'transaction_response' => json_encode($response),
@ -228,13 +241,21 @@ class CheckoutComPaymentDriver extends BaseDriver
'description' => $response['reference'],
'code' => 202,
];
} catch (CheckoutApiException $e) {
// API error
throw new PaymentFailed($e->getMessage(), $e->getCode());
} catch (CheckoutArgumentException $e) {
// Bad arguments
// throw new PaymentFailed($e->getMessage(), $e->getCode());
SystemLogger::dispatch(
$e->getMessage(),
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_CHECKOUT,
$payment->client,
$payment->company,
);
return [
'transaction_reference' => null,
@ -243,9 +264,17 @@ class CheckoutComPaymentDriver extends BaseDriver
'description' => $e->getMessage(),
'code' => $e->getCode(),
];
} catch (CheckoutAuthorizationException $e) {
// throw new PaymentFailed("The was a problem with the Checkout Gateway Credentials.", $e->getCode());
SystemLogger::dispatch(
$e->getMessage(),
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_CHECKOUT,
$payment->client,
$payment->company,
);
return [
'transaction_reference' => null,
@ -268,13 +297,14 @@ class CheckoutComPaymentDriver extends BaseDriver
$request = new CustomerRequest();
$phone = new Phone();
// $phone->number = $this->client->present()->phone();
$phone->number = substr(str_pad($this->client->present()->phone(), 6, "0", STR_PAD_RIGHT), 0, 24);
$request->email = $this->client->present()->email();
$request->name = $this->client->present()->name();
$request->phone = $phone;
// if($this->company_gateway->update_details)
// $this->updateCustomer();
try {
$response = $this->gateway->getCustomersClient()->create($request);
} catch (CheckoutApiException $e) {
@ -301,6 +331,27 @@ class CheckoutComPaymentDriver extends BaseDriver
}
}
public function updateCustomer()
{
$phone = new Phone();
$phone->number = substr(str_pad($this->client->present()->phone(), 6, "0", STR_PAD_RIGHT), 0, 24);
$request = new CustomerRequest();
$request->email = $this->client->present()->email();
$request->name = $this->client->present()->name();
$request->phone = $phone;
try {
$response = $this->gateway->getCustomersClient()->update("customer_id", $request);
} catch (CheckoutApiException $e) {
} catch (CheckoutAuthorizationException $e) {
}
}
/**
* Boots a request for a token payment
*

View File

@ -206,6 +206,7 @@ class PayPalExpressPaymentDriver extends BaseDriver
'transactionId' => $this->payment_hash->hash.'-'.time(),
'ButtonSource' => 'InvoiceNinja_SP',
'solutionType' => 'Sole',
'no_shipping' => $this->company_gateway->require_shipping_address ? 0 : 1,
];
}

View File

@ -142,6 +142,11 @@ class CreditCard implements MethodInterface
return $this->processSuccessfulPayment($response);
}
if(is_array($response)) {
nlog("square");
nlog($response);
}
return $this->processUnsuccessfulPayment($response);
}
@ -293,7 +298,7 @@ class CreditCard implements MethodInterface
$body->setFamilyName('');
$body->setEmailAddress($this->square_driver->client->present()->email());
$body->setAddress($billing_address);
$body->setPhoneNumber($this->square_driver->client->phone);
// $body->setPhoneNumber($this->square_driver->client->phone);
$body->setReferenceId($this->square_driver->client->number);
$body->setNote('Created by Invoice Ninja.');
@ -309,8 +314,8 @@ class CreditCard implements MethodInterface
return $result->getCustomer()->getId();
} else {
$errors = $api_response->getErrors();
return $this->processUnsuccessfulPayment($errors);
nlog($errors);
return $this->processUnsuccessfulPayment($api_response);
}
}
}

View File

@ -182,9 +182,9 @@ class FacturaEInvoice extends AbstractService
Storage::makeDirectory($this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()));
}
$this->fac->export(Storage::disk($disk)->path($this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()) . $this->invoice->getFileName("xsig")));
return $this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()) . $this->invoice->getFileName("xsig");
// $this->fac->export(Storage::disk($disk)->path($this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()) . $this->invoice->getFileName("xsig")));
return $this->fac->export();
// return $this->invoice->client->e_invoice_filepath($this->invoice->invitations->first()) . $this->invoice->getFileName("xsig");
}
@ -468,8 +468,11 @@ class FacturaEInvoice extends AbstractService
{
$company = $this->invoice->company;
if($company->getSetting('classification'))
return $this->setIndividualSeller();
$seller = new FacturaeParty([
"isLegalEntity" => $company->custom_value1, // Se asume true si se omite
"isLegalEntity" => true,
"taxNumber" => $company->settings->vat_number,
"name" => substr($company->present()->name(), 0, 40),
"address" => substr($company->settings->address1, 0, 80),
@ -500,11 +503,49 @@ class FacturaEInvoice extends AbstractService
return $this;
}
private function setIndividualSeller(): self
{
$company = $this->invoice->company;
$seller = new FacturaeParty([
"isLegalEntity" => false,
"taxNumber" => $company->settings->vat_number,
"name" => $company->getSetting('classification') === 'individual' ? substr($company->owner()->present()->name(), 0, 40) : substr($company->present()->name(), 0, 40),
"address" => substr($company->settings->address1, 0, 80),
"postCode" => substr($this->invoice->client->postal_code, 0, 5),
"town" => substr($company->settings->city, 0, 50),
"province" => substr($company->settings->state, 0, 20),
"countryCode" => $company->country()->iso_3166_3, // Se asume España si se omite
// "book" => "0", // Libro
// "merchantRegister" => "RG", // Registro Mercantil
// "sheet" => "1", // Hoja
// "folio" => "2", // Folio
// "section" => "3", // Sección
// "volume" => "4", // Tomo
"email" => substr($company->settings->email, 0, 60),
"phone" => substr($company->settings->phone, 0, 15),
"fax" => "",
"website" => substr($company->settings->website, 0, 50),
// "contactPeople" => substr($company->owner()->present()->name(), 0, 40),
"firstSurname" => $company->owner()->present()->firstName(),
"lastSurname" => $company->owner()->present()->lastName(),
]);
$this->fac->setSeller($seller);
return $this;
}
private function buildBuyer(): self
{
$buyer = new FacturaeParty([
"isLegalEntity" => $this->invoice->client->has_valid_vat_number,
"isLegalEntity" => $this->invoice->client->classification === 'individual' ? false : true,
"taxNumber" => $this->invoice->client->vat_number,
"name" => substr($this->invoice->client->present()->name(),0, 40),
"firstSurname" => substr($this->invoice->client->present()->first_name(),0, 40),

View File

@ -52,6 +52,7 @@ class MarkPaid extends AbstractService
$this->invoice
->service()
->setExchangeRate()
->clearPartial()
->updateBalance($this->payable_balance * -1)
->updatePaidToDate($this->payable_balance)
->setStatus(Invoice::STATUS_PAID)

View File

@ -29,7 +29,9 @@ class RefundPayment
private $credit_note;
private $total_refund;
private float $total_refund = 0;
private float $credits_used = 0;
private $gateway_refund_status;
@ -45,8 +47,6 @@ class RefundPayment
$this->refund_data = $refund_data;
$this->total_refund = 0;
$this->gateway_refund_status = false;
$this->activity_repository = new ActivityRepository();
@ -56,9 +56,9 @@ class RefundPayment
{
$this->payment = $this
->calculateTotalRefund() //sets amount for the refund (needed if we are refunding multiple invoices in one payment)
->updateCreditables() //return the credits first
->processGatewayRefund() //process the gateway refund if needed
->setStatus() //sets status of payment
->updateCreditables() //return the credits first
->updatePaymentables() //update the paymentable items
->adjustInvoices()
->finalize()
@ -104,12 +104,14 @@ class RefundPayment
*/
private function processGatewayRefund()
{
if ($this->refund_data['gateway_refund'] !== false && $this->total_refund > 0) {
$net_refund = ($this->total_refund - $this->credits_used);
if ($this->refund_data['gateway_refund'] !== false && $net_refund > 0) {
if ($this->payment->company_gateway) {
$response = $this->payment->company_gateway->driver($this->payment->client)->refund($this->payment, $this->total_refund);
$response = $this->payment->company_gateway->driver($this->payment->client)->refund($this->payment, $net_refund);
if($response['amount'] ?? false)
$this->total_refund = $response['amount'];
$net_refund = $response['amount'];
if($response['voided'] ?? false)
{
@ -123,7 +125,7 @@ class RefundPayment
})->toArray();
}
$this->payment->refunded += $this->total_refund;
$this->payment->refunded += $net_refund;
if ($response['success'] == false) {
$this->payment->save();
@ -132,7 +134,7 @@ class RefundPayment
}
}
} else {
$this->payment->refunded += $this->total_refund;
$this->payment->refunded += $net_refund;
}
return $this;
@ -227,23 +229,29 @@ class RefundPayment
*/
private function updateCreditables()
{
if ($this->payment->credits()->exists()) {
$amount_to_refund = $this->total_refund;
//Adjust credits first!!!
foreach ($this->payment->credits as $paymentable_credit) {
$available_credit = $paymentable_credit->pivot->amount - $paymentable_credit->pivot->refunded;
if ($available_credit > $this->total_refund) {
$paymentable_credit->pivot->refunded += $this->total_refund;
if ($available_credit > $amount_to_refund) {
$paymentable_credit->pivot->refunded += $amount_to_refund;
$paymentable_credit->pivot->save();
$paymentable_credit->service()
->setStatus(Credit::STATUS_SENT)
->updateBalance($this->total_refund)
->updatePaidToDate($this->total_refund * -1)
->adjustBalance($amount_to_refund)
->updatePaidToDate($amount_to_refund * -1)
->save();
$this->total_refund = 0;
$this->credits_used += $amount_to_refund;
$amount_to_refund = 0;
} else {
$paymentable_credit->pivot->refunded += $available_credit;
$paymentable_credit->pivot->save();
@ -254,10 +262,12 @@ class RefundPayment
->updatePaidToDate($available_credit * -1)
->save();
$this->total_refund -= $available_credit;
$this->credits_used += $available_credit;
$amount_to_refund -= $available_credit;
}
if ($this->total_refund == 0) {
if ($amount_to_refund == 0) {
break;
}
}

172
composer.lock generated
View File

@ -485,16 +485,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.281.12",
"version": "3.282.0",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "22a92f08758db2b152843ea0875eeee5a467d8ff"
"reference": "79a3ed5bb573f592823f8b1cffe0dbac3132e6b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/22a92f08758db2b152843ea0875eeee5a467d8ff",
"reference": "22a92f08758db2b152843ea0875eeee5a467d8ff",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/79a3ed5bb573f592823f8b1cffe0dbac3132e6b4",
"reference": "79a3ed5bb573f592823f8b1cffe0dbac3132e6b4",
"shasum": ""
},
"require": {
@ -574,9 +574,9 @@
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.281.12"
"source": "https://github.com/aws/aws-sdk-php/tree/3.282.0"
},
"time": "2023-09-22T18:12:27+00:00"
"time": "2023-09-28T18:09:20+00:00"
},
{
"name": "bacon/bacon-qr-code",
@ -1353,16 +1353,16 @@
},
{
"name": "doctrine/dbal",
"version": "3.6.7",
"version": "3.7.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "8e0e268052b4a8974cb00215bb2892787021614f"
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/8e0e268052b4a8974cb00215bb2892787021614f",
"reference": "8e0e268052b4a8974cb00215bb2892787021614f",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/00d03067f07482f025d41ab55e4ba0db5eca2cdf",
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf",
"shasum": ""
},
"require": {
@ -1378,9 +1378,9 @@
"doctrine/coding-standard": "12.0.0",
"fig/log-test": "^1",
"jetbrains/phpstorm-stubs": "2023.1",
"phpstan/phpstan": "1.10.34",
"phpstan/phpstan": "1.10.35",
"phpstan/phpstan-strict-rules": "^1.5",
"phpunit/phpunit": "9.6.12",
"phpunit/phpunit": "9.6.13",
"psalm/plugin-phpunit": "0.18.4",
"slevomat/coding-standard": "8.13.1",
"squizlabs/php_codesniffer": "3.7.2",
@ -1446,7 +1446,7 @@
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/3.6.7"
"source": "https://github.com/doctrine/dbal/tree/3.7.0"
},
"funding": [
{
@ -1462,20 +1462,20 @@
"type": "tidelift"
}
],
"time": "2023-09-19T20:15:41+00:00"
"time": "2023-09-26T20:56:55+00:00"
},
{
"name": "doctrine/deprecations",
"version": "v1.1.1",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3"
"reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
"reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
"shasum": ""
},
"require": {
@ -1507,9 +1507,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v1.1.1"
"source": "https://github.com/doctrine/deprecations/tree/1.1.2"
},
"time": "2023-06-03T09:27:29+00:00"
"time": "2023-09-27T20:04:15+00:00"
},
{
"name": "doctrine/event-manager",
@ -4287,16 +4287,16 @@
},
{
"name": "laravel/framework",
"version": "v10.24.0",
"version": "v10.25.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "bcebd0a4c015d5c38aeec299d355a42451dd3726"
"reference": "6014dd456b414b305fb0b408404efdcec18e64bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/bcebd0a4c015d5c38aeec299d355a42451dd3726",
"reference": "bcebd0a4c015d5c38aeec299d355a42451dd3726",
"url": "https://api.github.com/repos/laravel/framework/zipball/6014dd456b414b305fb0b408404efdcec18e64bc",
"reference": "6014dd456b414b305fb0b408404efdcec18e64bc",
"shasum": ""
},
"require": {
@ -4314,7 +4314,7 @@
"ext-tokenizer": "*",
"fruitcake/php-cors": "^1.2",
"guzzlehttp/uri-template": "^1.0",
"laravel/prompts": "^0.1",
"laravel/prompts": "^0.1.9",
"laravel/serializable-closure": "^1.3",
"league/commonmark": "^2.2.1",
"league/flysystem": "^3.8.0",
@ -4396,7 +4396,7 @@
"league/flysystem-read-only": "^3.3",
"league/flysystem-sftp-v3": "^3.0",
"mockery/mockery": "^1.5.1",
"orchestra/testbench-core": "^8.10",
"orchestra/testbench-core": "^8.12",
"pda/pheanstalk": "^4.0",
"phpstan/phpstan": "^1.4.7",
"phpunit/phpunit": "^10.0.7",
@ -4483,20 +4483,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2023-09-19T15:25:04+00:00"
"time": "2023-09-28T14:08:59+00:00"
},
{
"name": "laravel/prompts",
"version": "v0.1.8",
"version": "v0.1.10",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
"reference": "68dcc65babf92e1fb43cba0b3f78fc3d8002709c"
"reference": "37ed55f6950d921a87d5beeab16d03f8de26b060"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/68dcc65babf92e1fb43cba0b3f78fc3d8002709c",
"reference": "68dcc65babf92e1fb43cba0b3f78fc3d8002709c",
"url": "https://api.github.com/repos/laravel/prompts/zipball/37ed55f6950d921a87d5beeab16d03f8de26b060",
"reference": "37ed55f6950d921a87d5beeab16d03f8de26b060",
"shasum": ""
},
"require": {
@ -4505,6 +4505,10 @@
"php": "^8.1",
"symfony/console": "^6.2"
},
"conflict": {
"illuminate/console": ">=10.17.0 <10.25.0",
"laravel/framework": ">=10.17.0 <10.25.0"
},
"require-dev": {
"mockery/mockery": "^1.5",
"pestphp/pest": "^2.3",
@ -4515,6 +4519,11 @@
"ext-pcntl": "Required for the spinner to be animated."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "0.1.x-dev"
}
},
"autoload": {
"files": [
"src/helpers.php"
@ -4529,9 +4538,9 @@
],
"support": {
"issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.1.8"
"source": "https://github.com/laravel/prompts/tree/v0.1.10"
},
"time": "2023-09-19T15:33:56+00:00"
"time": "2023-09-29T07:26:07+00:00"
},
{
"name": "laravel/serializable-closure",
@ -5825,16 +5834,16 @@
},
{
"name": "microsoft/microsoft-graph",
"version": "1.106.0",
"version": "1.107.0",
"source": {
"type": "git",
"url": "https://github.com/microsoftgraph/msgraph-sdk-php.git",
"reference": "a9f43d74131bb13cb1b5a999101d486b26601b8f"
"reference": "63fed05d4d9c348db094f8d8a1d44ff9ce6887c7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/a9f43d74131bb13cb1b5a999101d486b26601b8f",
"reference": "a9f43d74131bb13cb1b5a999101d486b26601b8f",
"url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/63fed05d4d9c348db094f8d8a1d44ff9ce6887c7",
"reference": "63fed05d4d9c348db094f8d8a1d44ff9ce6887c7",
"shasum": ""
},
"require": {
@ -5871,9 +5880,9 @@
"homepage": "https://developer.microsoft.com/en-us/graph",
"support": {
"issues": "https://github.com/microsoftgraph/msgraph-sdk-php/issues",
"source": "https://github.com/microsoftgraph/msgraph-sdk-php/tree/1.106.0"
"source": "https://github.com/microsoftgraph/msgraph-sdk-php/tree/1.107.0"
},
"time": "2023-09-08T06:02:27+00:00"
"time": "2023-09-27T06:43:40+00:00"
},
{
"name": "mollie/mollie-api-php",
@ -6361,16 +6370,16 @@
},
{
"name": "nesbot/carbon",
"version": "2.70.0",
"version": "2.71.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d"
"reference": "98276233188583f2ff845a0f992a235472d9466a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d3298b38ea8612e5f77d38d1a99438e42f70341d",
"reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/98276233188583f2ff845a0f992a235472d9466a",
"reference": "98276233188583f2ff845a0f992a235472d9466a",
"shasum": ""
},
"require": {
@ -6463,7 +6472,7 @@
"type": "tidelift"
}
],
"time": "2023-09-07T16:43:50+00:00"
"time": "2023-09-25T11:31:05+00:00"
},
{
"name": "nette/schema",
@ -8127,16 +8136,16 @@
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.24.1",
"version": "1.24.2",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01"
"reference": "bcad8d995980440892759db0c32acae7c8e79442"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01",
"reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442",
"reference": "bcad8d995980440892759db0c32acae7c8e79442",
"shasum": ""
},
"require": {
@ -8168,9 +8177,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.1"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.2"
},
"time": "2023-09-18T12:18:02+00:00"
"time": "2023-09-26T12:28:12+00:00"
},
{
"name": "pragmarx/google2fa",
@ -9689,16 +9698,16 @@
},
{
"name": "setasign/fpdi",
"version": "v2.4.1",
"version": "v2.5.0",
"source": {
"type": "git",
"url": "https://github.com/Setasign/FPDI.git",
"reference": "f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b"
"reference": "ecf0459643ec963febfb9a5d529dcd93656006a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b",
"reference": "f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b",
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/ecf0459643ec963febfb9a5d529dcd93656006a4",
"reference": "ecf0459643ec963febfb9a5d529dcd93656006a4",
"shasum": ""
},
"require": {
@ -9749,7 +9758,7 @@
],
"support": {
"issues": "https://github.com/Setasign/FPDI/issues",
"source": "https://github.com/Setasign/FPDI/tree/v2.4.1"
"source": "https://github.com/Setasign/FPDI/tree/v2.5.0"
},
"funding": [
{
@ -9757,7 +9766,7 @@
"type": "tidelift"
}
],
"time": "2023-07-27T08:12:09+00:00"
"time": "2023-09-28T10:46:27+00:00"
},
{
"name": "shopify/shopify-api",
@ -10330,16 +10339,16 @@
},
{
"name": "stripe/stripe-php",
"version": "v12.4.0",
"version": "v12.5.0",
"source": {
"type": "git",
"url": "https://github.com/stripe/stripe-php.git",
"reference": "7d0a90772fc1c179e370971264318208533324b9"
"reference": "a4249b4a90437844f6c35e8701f8c68acd206f56"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/7d0a90772fc1c179e370971264318208533324b9",
"reference": "7d0a90772fc1c179e370971264318208533324b9",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/a4249b4a90437844f6c35e8701f8c68acd206f56",
"reference": "a4249b4a90437844f6c35e8701f8c68acd206f56",
"shasum": ""
},
"require": {
@ -10384,9 +10393,9 @@
],
"support": {
"issues": "https://github.com/stripe/stripe-php/issues",
"source": "https://github.com/stripe/stripe-php/tree/v12.4.0"
"source": "https://github.com/stripe/stripe-php/tree/v12.5.0"
},
"time": "2023-09-21T22:55:47+00:00"
"time": "2023-09-28T23:06:27+00:00"
},
{
"name": "symfony/console",
@ -15037,16 +15046,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.28.0",
"version": "v3.34.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "113e09fea3d2306319ffaa2423fe3de768b28cff"
"reference": "7c7a4ad2ed8fe50df3e25528218b13d383608f23"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/113e09fea3d2306319ffaa2423fe3de768b28cff",
"reference": "113e09fea3d2306319ffaa2423fe3de768b28cff",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7c7a4ad2ed8fe50df3e25528218b13d383608f23",
"reference": "7c7a4ad2ed8fe50df3e25528218b13d383608f23",
"shasum": ""
},
"require": {
@ -15067,6 +15076,9 @@
"symfony/process": "^5.4 || ^6.0",
"symfony/stopwatch": "^5.4 || ^6.0"
},
"conflict": {
"stevebauman/unfinalize": "*"
},
"require-dev": {
"facile-it/paraunit": "^1.3 || ^2.0",
"justinrainbow/json-schema": "^5.2",
@ -15120,7 +15132,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.28.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.34.0"
},
"funding": [
{
@ -15128,7 +15140,7 @@
"type": "github"
}
],
"time": "2023-09-22T20:43:40+00:00"
"time": "2023-09-29T15:34:26+00:00"
},
{
"name": "hamcrest/hamcrest-php",
@ -15839,16 +15851,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.10.35",
"version": "1.10.36",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3"
"reference": "ffa3089511121a672e62969404e4fddc753f9b15"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e730e5facb75ffe09dfb229795e8c01a459f26c3",
"reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/ffa3089511121a672e62969404e4fddc753f9b15",
"reference": "ffa3089511121a672e62969404e4fddc753f9b15",
"shasum": ""
},
"require": {
@ -15897,7 +15909,7 @@
"type": "tidelift"
}
],
"time": "2023-09-19T15:27:56+00:00"
"time": "2023-09-29T14:07:45+00:00"
},
{
"name": "phpunit/php-code-coverage",
@ -16567,16 +16579,16 @@
},
{
"name": "sebastian/complexity",
"version": "3.0.1",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/complexity.git",
"reference": "c70b73893e10757af9c6a48929fa6a333b56a97a"
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c70b73893e10757af9c6a48929fa6a333b56a97a",
"reference": "c70b73893e10757af9c6a48929fa6a333b56a97a",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957",
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957",
"shasum": ""
},
"require": {
@ -16589,7 +16601,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.0-dev"
"dev-main": "3.1-dev"
}
},
"autoload": {
@ -16613,7 +16625,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/complexity/issues",
"security": "https://github.com/sebastianbergmann/complexity/security/policy",
"source": "https://github.com/sebastianbergmann/complexity/tree/3.0.1"
"source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0"
},
"funding": [
{
@ -16621,7 +16633,7 @@
"type": "github"
}
],
"time": "2023-08-31T09:55:53+00:00"
"time": "2023-09-28T11:50:59+00:00"
},
{
"name": "sebastian/diff",

View File

@ -15,8 +15,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => env('APP_VERSION','5.7.22'),
'app_tag' => env('APP_TAG','5.7.22'),
'app_version' => env('APP_VERSION','5.7.23'),
'app_tag' => env('APP_TAG','5.7.23'),
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),

View File

@ -5176,7 +5176,7 @@ $LANG = array(
'email_delivered' => 'Email Delivered',
'log' => 'Log',
'classification' => 'Classification',
'stock_quantity' => 'Stock :quantity',
'stock_quantity_number' => 'Stock :quantity',
);
return $LANG;

View File

@ -16,6 +16,8 @@ trait CreatesApplication
{
$app = require __DIR__.'/../bootstrap/app.php';
define('STDIN', fopen("php://stdin", "r"));
$app->make(Kernel::class)->bootstrap();
Hash::setRounds(4);

View File

@ -73,7 +73,7 @@ class ClassificationTest extends TestCase
public function testValidation2Classification()
{
$this->client->classification = 'company';
$this->client->classification = 'business';
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
@ -84,7 +84,7 @@ class ClassificationTest extends TestCase
$arr = $response->json();
$this->assertEquals('company', $arr['data']['classification']);
$this->assertEquals('business', $arr['data']['classification']);
}
public function testValidation3Classification()

View File

@ -497,7 +497,7 @@ class PaymentTest extends TestCase
'is_primary' => 1,
]);
/** @var \App\Models\Invoice $invoice */
$invoice = InvoiceFactory::create($this->company->id, $this->user->id); //stub the company and user_id
$invoice->client_id = $client->id;
@ -1310,15 +1310,14 @@ class PaymentTest extends TestCase
];
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/payments?include=invoices', $data);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
$this->assertNotNull($message);
}
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/payments?include=invoices', $data);
$response->assertStatus(422);
}
public function testPaymentWithSameInvoiceMultipleTimes()

View File

@ -11,21 +11,22 @@
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\Payment;
use Tests\MockAccountData;
use App\Models\ClientContact;
use App\Factory\ClientFactory;
use App\Factory\CreditFactory;
use App\Factory\InvoiceFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Models\ClientContact;
use App\Models\Invoice;
use App\Models\Payment;
use App\Utils\Traits\MakesHash;
use App\Helpers\Invoice\InvoiceSum;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\ValidationException;
use Tests\MockAccountData;
use Tests\TestCase;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Foundation\Testing\DatabaseTransactions;
/**
* @test
@ -37,6 +38,8 @@ class RefundTest extends TestCase
use DatabaseTransactions;
use MockAccountData;
public $faker;
protected function setUp() :void
{
parent::setUp();
@ -53,7 +56,7 @@ class RefundTest extends TestCase
$this->makeTestData();
$this->withoutExceptionHandling();
// $this->withoutExceptionHandling();
}
/**
@ -82,10 +85,10 @@ class RefundTest extends TestCase
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$invoice_calc = new InvoiceSum($this->invoice);
$invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice = $invoice_calc->getInvoice();
$this->invoice->save();
$data = [
@ -119,14 +122,12 @@ class RefundTest extends TestCase
$response = false;
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/payments/refund', $data);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
}
])->postJson('/api/v1/payments/refund', $data);
$arr = $response->json();
@ -165,10 +166,10 @@ class RefundTest extends TestCase
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$invoice_calc = new InvoiceSum($this->invoice);
$invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice = $invoice_calc->getInvoice();
$this->invoice->save();
$this->invoice->setRelation('client', $this->client);
@ -217,23 +218,12 @@ class RefundTest extends TestCase
'date' => '2020/12/12',
];
$response = false;
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/payments/refund', $data);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
$this->assertNotNull($message);
\Log::error($message);
}
if ($response) {
$response->assertStatus(302);
}
])->postJson('/api/v1/payments/refund', $data);
$response->assertStatus(422);
}
/**
@ -262,10 +252,10 @@ class RefundTest extends TestCase
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$invoice_calc = new InvoiceSum($this->invoice);
$invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice = $invoice_calc->getInvoice();
$this->invoice->save();
$data = [
@ -346,10 +336,10 @@ class RefundTest extends TestCase
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$invoice_calc = new InvoiceSum($this->invoice);
$invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice = $invoice_calc->getInvoice();
$this->invoice->save();
$data = [
@ -439,10 +429,10 @@ class RefundTest extends TestCase
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$invoice_calc = new InvoiceSum($this->invoice);
$invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice = $invoice_calc->getInvoice();
$this->invoice->save();
$data = [
@ -485,10 +475,10 @@ class RefundTest extends TestCase
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$invoice_calc = new InvoiceSum($this->invoice);
$invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice = $invoice_calc->getInvoice();
$this->invoice->save();
$data = [
@ -553,13 +543,13 @@ class RefundTest extends TestCase
$this->invoice->line_items = $this->buildLineItems();
$this->invoice->uses_inclusive_taxes = false;
$this->invoice_client_id = $client->id;
$this->invoice->client_id = $client->id;
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$invoice_calc = new InvoiceSum($this->invoice);
$invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice = $invoice_calc->getInvoice();
$this->invoice->save();
$this->credit = CreditFactory::create($this->company->id, $this->user->id);
@ -650,4 +640,172 @@ class RefundTest extends TestCase
}
/*Additional scenarios*/
public function testRefundsWhenCreditsArePresent()
{
$i = Invoice::factory()->create([
'company_id' => $this->company->id,
'user_id' => $this->user->id,
'client_id' => $this->client->id,
'status_id' => Invoice::STATUS_SENT,
'amount' => 1000,
'balance' => 1000,
]);
$c = Credit::factory()->create([
'company_id' => $this->company->id,
'user_id' => $this->user->id,
'client_id' => $this->client->id,
'status_id' => Invoice::STATUS_SENT,
'amount' => 100,
'balance' => 100,
]);
$data = [
'client_id' => $this->client->hashed_id,
'invoices' => [
[
'invoice_id' => $i->hashed_id,
'amount' => 1000,
],
],
'credits' => [
[
'credit_id' => $c->hashed_id,
'amount' => 100,
],
],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/payments', $data);
$arr = $response->json();
$response->assertStatus(200);
$this->assertEquals(0, $c->fresh()->balance);
$this->assertEquals(0, $i->fresh()->balance);
$payment_id = $arr['data']['id'];
$refund = [
'id' => $payment_id,
'client_id' => $this->client->hashed_id,
'amount' => 10,
'date' => now()->format('Y-m-d'),
'invoices' => [
[
'invoice_id' => $i->hashed_id,
'amount' => 10,
],
]
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/payments/refund', $refund);
$response->assertStatus(200);
$arr = $response->json();
$this->assertEquals(0, $arr['data']['refunded']);
$this->assertEquals(10, $c->fresh()->balance);
$this->assertEquals(10, $i->fresh()->balance);
}
public function testRefundsWithSplitCreditAndPaymentRefund()
{
$i = Invoice::factory()->create([
'company_id' => $this->company->id,
'user_id' => $this->user->id,
'client_id' => $this->client->id,
'status_id' => Invoice::STATUS_SENT,
'amount' => 1000,
'balance' => 1000,
]);
$c = Credit::factory()->create([
'company_id' => $this->company->id,
'user_id' => $this->user->id,
'client_id' => $this->client->id,
'status_id' => Invoice::STATUS_SENT,
'amount' => 100,
'balance' => 100,
]);
$data = [
'client_id' => $this->client->hashed_id,
'invoices' => [
[
'invoice_id' => $i->hashed_id,
'amount' => 1000,
],
],
'credits' => [
[
'credit_id' => $c->hashed_id,
'amount' => 100,
],
],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/payments', $data);
$arr = $response->json();
$response->assertStatus(200);
$this->assertEquals(0, $c->fresh()->balance);
$this->assertEquals(0, $i->fresh()->balance);
$payment_id = $arr['data']['id'];
$payment = Payment::find($this->decodePrimaryKey($payment_id));
$this->assertEquals(900, $payment->amount);
$this->assertEquals(900, $payment->applied);
$this->assertEquals(0, $payment->refunded);
$refund = [
'id' => $payment_id,
'client_id' => $this->client->hashed_id,
'amount' => 200,
'date' => now()->format('Y-m-d'),
'invoices' => [
[
'invoice_id' => $i->hashed_id,
'amount' => 200,
],
]
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/payments/refund', $refund);
$response->assertStatus(200);
$arr = $response->json();
$this->assertEquals(100, $arr['data']['refunded']);
$this->assertEquals(100, $c->fresh()->balance);
$this->assertEquals(200, $i->fresh()->balance);
$this->assertEquals(900, $payment->fresh()->amount);
$this->assertEquals(900, $payment->fresh()->applied);
$this->assertEquals(100, $payment->fresh()->refunded);
}
}

View File

@ -11,13 +11,15 @@
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\Company;
use App\Models\TaxRate;
use Tests\MockAccountData;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\ValidationException;
use Tests\MockAccountData;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;
/**
* @test
@ -44,6 +46,44 @@ class TaxRateApiTest extends TestCase
Model::reguard();
}
public function testRemovingDefaultTaxes()
{
$t = TaxRate::factory()->create([
'company_id' => $this->company->id,
'user_id' => $this->user->id,
'name' => 'nastytax1',
'rate' => 10,
]);
$settings = $this->company->settings;
$settings->tax_rate1 = $t->rate;
$settings->tax_name1 = $t->name;
$this->company->saveSettings($settings, $this->company);
$this->company->fresh();
$this->assertEquals('nastytax1', $this->company->settings->tax_name1);
$this->assertEquals(10, $this->company->settings->tax_rate1);
$data = [
'ids' => [$this->encodePrimaryKey($t->id)],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/tax_rates/bulk?action=archive', $data);
$response->assertStatus(200);
$this->company = $this->company->fresh();
$this->assertEquals('', $this->company->getSetting('tax_name1'));
$this->assertEquals(0, $this->company->getSetting('tax_rate1'));
}
public function testTaxRatesGetFilter()
{
$response = $this->withHeaders([

View File

@ -43,6 +43,8 @@ class CompanyLedgerTest extends TestCase
public $account;
public $faker;
protected function setUp() :void
{
parent::setUp();

View File

@ -11,57 +11,58 @@
namespace Tests;
use App\DataMapper\ClientRegistrationFields;
use App\DataMapper\ClientSettings;
use App\DataMapper\CompanySettings;
use App\Factory\CompanyUserFactory;
use App\Factory\CreditFactory;
use App\Factory\InvoiceFactory;
use App\Factory\InvoiceInvitationFactory;
use App\Factory\InvoiceItemFactory;
use App\Factory\InvoiceToRecurringInvoiceFactory;
use App\Factory\PurchaseOrderFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Jobs\Company\CreateCompanyTaskStatuses;
use App\Models\Account;
use App\Models\BankIntegration;
use App\Models\BankTransaction;
use App\Models\BankTransactionRule;
use App\Models\Task;
use App\Models\User;
use App\Models\Quote;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Company;
use App\Models\CompanyGateway;
use App\Models\CompanyToken;
use App\Models\Credit;
use App\Models\CreditInvitation;
use App\Models\Vendor;
use App\Models\Account;
use App\Models\Company;
use App\Models\Expense;
use App\Models\ExpenseCategory;
use App\Models\GroupSetting;
use App\Models\InvoiceInvitation;
use App\Models\Payment;
use App\Models\Product;
use App\Models\Project;
use App\Models\PurchaseOrderInvitation;
use App\Models\Quote;
use App\Models\TaxRate;
use App\Models\Scheduler;
use App\Models\TaskStatus;
use App\Utils\TruthSource;
use App\Models\CompanyToken;
use App\Models\GroupSetting;
use App\Models\ClientContact;
use App\Models\VendorContact;
use App\Factory\CreditFactory;
use App\Models\CompanyGateway;
use App\Models\RecurringQuote;
use Illuminate\Support\Carbon;
use App\Factory\InvoiceFactory;
use App\Models\BankIntegration;
use App\Models\BankTransaction;
use App\Models\ExpenseCategory;
use App\Models\QuoteInvitation;
use App\Utils\Traits\MakesHash;
use App\Models\CreditInvitation;
use App\Models\RecurringExpense;
use App\Models\RecurringInvoice;
use App\Models\RecurringQuote;
use App\Models\Scheduler;
use App\Models\Task;
use App\Models\TaskStatus;
use App\Models\TaxRate;
use App\Models\User;
use App\Models\Vendor;
use App\Models\VendorContact;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesHash;
use App\Utils\TruthSource;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use App\Models\InvoiceInvitation;
use App\DataMapper\ClientSettings;
use App\DataMapper\CompanySettings;
use App\Factory\CompanyUserFactory;
use App\Factory\InvoiceItemFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Models\BankTransactionRule;
use Illuminate\Support\Facades\Hash;
use App\Factory\PurchaseOrderFactory;
use Illuminate\Support\Facades\Cache;
use App\Utils\Traits\GeneratesCounter;
use Illuminate\Support\Facades\Schema;
use App\Models\PurchaseOrderInvitation;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Storage;
use App\Factory\InvoiceInvitationFactory;
use App\DataMapper\ClientRegistrationFields;
use App\Jobs\Company\CreateCompanyTaskStatuses;
use App\Factory\InvoiceToRecurringInvoiceFactory;
/**
* Class MockAccountData.
@ -200,7 +201,9 @@ trait MockAccountData
/* Warm up the cache !*/
$cached_tables = config('ninja.cached_tables');
$this->artisan('db:seed --force');
Artisan::call('db:seed', [
'--force' => true
]);
foreach ($cached_tables as $name => $class) {
// check that the table exists in case the migration is pending

View File

@ -49,7 +49,36 @@ class InvoiceTest extends TestCase
$this->invoice_calc = new InvoiceSum($this->invoice);
}
public function testGrossTaxAmountCalcuations()
public function testMarkPaidWithPartial()
{
$item = InvoiceItemFactory::create();
$item->quantity = 1;
$item->cost = 50;
$line_items[] = $item;
$this->invoice->partial = 5;
$this->invoice->partial_due_date = now()->addDay();
$this->invoice->due_date = now()->addDays(10);
$this->invoice->line_items = $line_items;
$this->invoice->save();
$invoice_calc = new InvoiceSum($this->invoice);
$invoice = $invoice_calc->build()->getInvoice()->service()->markSent()->save();
$this->assertEquals(5, $invoice->partial);
$this->assertNotNull($invoice->partial_due_date);
$this->assertEquals(50, $invoice->amount);
$invoice = $invoice->service()->markPaid()->save();
$this->assertEquals(0, $invoice->partial);
$this->assertEquals(0, $invoice->balance);
$this->assertNull($invoice->partial_due_date);
}
public function testGrossTaxAmountCalcuations()
{
$invoice = InvoiceFactory::create($this->company->id, $this->user->id);
$invoice->client_id = $this->client->id;