Merge pull request #6829 from turbo124/v5-develop

Minor fixes for Statements
This commit is contained in:
David Bomba 2021-10-13 14:16:47 +11:00 committed by GitHub
commit 5118a01e7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 497 additions and 92 deletions

View File

@ -496,6 +496,7 @@ class DesignController extends BaseController
$company = auth()->user()->getCompany(); $company = auth()->user()->getCompany();
$design = Design::where('company_id', $company->id) $design = Design::where('company_id', $company->id)
->orWhereNull('company_id')
->where('id', $design_id) ->where('id', $design_id)
->exists(); ->exists();

View File

@ -204,6 +204,7 @@ class PreviewController extends BaseController
if($request->has('entity_id')){ if($request->has('entity_id')){
$entity_obj = $class::on(config('database.default')) $entity_obj = $class::on(config('database.default'))
->with('client.company')
->where('id', $this->decodePrimaryKey($request->input('entity_id'))) ->where('id', $this->decodePrimaryKey($request->input('entity_id')))
->where('company_id', $company->id) ->where('company_id', $company->id)
->withTrashed() ->withTrashed()
@ -216,11 +217,11 @@ class PreviewController extends BaseController
if(!$request->has('entity_id')) if(!$request->has('entity_id'))
$entity_obj->service()->fillDefaults()->save(); $entity_obj->service()->fillDefaults()->save();
$entity_obj->load('client.contacts','company'); // $entity_obj->load('client.contacts','client.company');
App::forgetInstance('translator'); App::forgetInstance('translator');
$t = app('translator'); $t = app('translator');
App::setLocale($entity_obj->client->contacts()->first()->preferredLocale()); App::setLocale($entity_obj->client->locale());
$t->replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings())); $t->replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings()));
$html = new HtmlEngine($entity_obj->invitations()->first()); $html = new HtmlEngine($entity_obj->invitations()->first());

View File

@ -268,7 +268,7 @@ class BillingPortalPurchase extends Component
$client = $client_repo->save($data, ClientFactory::create($company->id, $user->id)); $client = $client_repo->save($data, ClientFactory::create($company->id, $user->id));
return $client->contacts->first(); return $client->fresh()->contacts->first();
} }
/** /**

View File

@ -39,8 +39,6 @@ class StorePaymentRequest extends Request
{ {
$input = $this->all(); $input = $this->all();
// nlog(print_r($input,1));
$invoices_total = 0; $invoices_total = 0;
$credits_total = 0; $credits_total = 0;

View File

@ -51,6 +51,6 @@ class CreateStatementRequest extends Request
public function client(): ?Client public function client(): ?Client
{ {
return Client::where('id', $this->client_id)->first(); return Client::with('company')->where('id', $this->client_id)->withTrashed()->first();
} }
} }

View File

@ -336,6 +336,14 @@ class CompanyExport implements ShouldQueue
})->all(); })->all();
$this->export_data['recurring_expenses'] = $this->company->recurring_expenses->map(function ($expense){
$expense = $this->transformBasicEntities($expense);
$expense = $this->transformArrayOfKeys($expense, ['vendor_id', 'invoice_id', 'client_id', 'category_id', 'project_id']);
return $expense->makeVisible(['id']);
})->all();
$this->export_data['recurring_invoices'] = $this->company->recurring_invoices->makeVisible(['id'])->map(function ($ri){ $this->export_data['recurring_invoices'] = $this->company->recurring_invoices->makeVisible(['id'])->map(function ($ri){

View File

@ -47,6 +47,7 @@ use App\Models\Product;
use App\Models\Project; use App\Models\Project;
use App\Models\Quote; use App\Models\Quote;
use App\Models\QuoteInvitation; use App\Models\QuoteInvitation;
use App\Models\RecurringExpense;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\Models\RecurringInvoiceInvitation; use App\Models\RecurringInvoiceInvitation;
use App\Models\Subscription; use App\Models\Subscription;
@ -76,6 +77,8 @@ use ZipArchive;
use ZipStream\Option\Archive; use ZipStream\Option\Archive;
use ZipStream\ZipStream; use ZipStream\ZipStream;
use function GuzzleHttp\json_encode;
class CompanyImport implements ShouldQueue class CompanyImport implements ShouldQueue
{ {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash, GeneratesCounter; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash, GeneratesCounter;
@ -135,6 +138,7 @@ class CompanyImport implements ShouldQueue
'quote_invitations', 'quote_invitations',
'credits', 'credits',
'credit_invitations', 'credit_invitations',
'recurring_expenses',
'expenses', 'expenses',
'tasks', 'tasks',
'payments', 'payments',
@ -452,6 +456,26 @@ class CompanyImport implements ShouldQueue
} }
private function import_recurring_expenses()
{
//unset / transforms / object_property / match_key
$this->genericImport(RecurringExpense::class,
['assigned_user_id', 'user_id', 'client_id', 'company_id', 'id', 'hashed_id', 'project_id', 'vendor_id'],
[
['users' => 'user_id'],
['users' => 'assigned_user_id'],
['clients' => 'client_id'],
['projects' => 'project_id'],
['vendors' => 'vendor_id'],
['invoices' => 'invoice_id'],
['expense_categories' => 'category_id'],
],
'expenses',
'number');
return $this;
}
private function import_payment_terms() private function import_payment_terms()
{ {
@ -795,6 +819,8 @@ class CompanyImport implements ShouldQueue
['projects' => 'project_id'], ['projects' => 'project_id'],
['vendors' => 'vendor_id'], ['vendors' => 'vendor_id'],
['invoices' => 'invoice_id'], ['invoices' => 'invoice_id'],
['recurring_expenses' => 'recurring_expense_id'],
['expense_categories' => 'category_id'],
], ],
'expenses', 'expenses',
'number'); 'number');
@ -1248,6 +1274,7 @@ class CompanyImport implements ShouldQueue
if($class == 'App\Models\Subscription'){ if($class == 'App\Models\Subscription'){
$obj_array['product_ids'] = $this->recordProductIds($obj_array['product_ids']); $obj_array['product_ids'] = $this->recordProductIds($obj_array['product_ids']);
$obj_array['recurring_product_ids'] = $this->recordProductIds($obj_array['recurring_product_ids']); $obj_array['recurring_product_ids'] = $this->recordProductIds($obj_array['recurring_product_ids']);
$obj_array['webhook_configuration'] = json_encode($obj_array['webhook_configuration']);
} }
$new_obj = $class::firstOrNew( $new_obj = $class::firstOrNew(
@ -1297,7 +1324,8 @@ class CompanyImport implements ShouldQueue
if($class == 'App\Models\Subscription'){ if($class == 'App\Models\Subscription'){
//$obj_array['product_ids'] = $this->recordProductIds($obj_array['product_ids']); //$obj_array['product_ids'] = $this->recordProductIds($obj_array['product_ids']);
//$obj_array['recurring_product_ids'] = $this->recordProductIds($obj_array['recurring_product_ids']); //$obj_array['recurring_product_ids'] = $this->recordProductIds($obj_array['recurring_product_ids']);
// // $obj_array['webhook_configuration'] = json_encode($obj_array['webhook_configuration']);
$obj_array['webhook_configuration'] = '';
$obj_array['recurring_product_ids'] = ''; $obj_array['recurring_product_ids'] = '';
$obj_array['product_ids'] = ''; $obj_array['product_ids'] = '';
} }

View File

@ -46,7 +46,7 @@ class PaymentEmailEngine extends BaseEmailEngine
$this->payment = $payment; $this->payment = $payment;
$this->company = $payment->company; $this->company = $payment->company;
$this->client = $payment->client; $this->client = $payment->client;
$this->contact = $contact ?: $this->client->primary_contact()->first(); $this->contact = $contact ?: $this->client->contacts()->first();
$this->contact->load('client.company'); $this->contact->load('client.company');
$this->settings = $this->client->getMergedSettings(); $this->settings = $this->client->getMergedSettings();
$this->template_data = $template_data; $this->template_data = $template_data;

View File

@ -61,7 +61,7 @@ class Gateway extends StaticModel
$link = 'https://bitpay.com/dashboard/signup'; $link = 'https://bitpay.com/dashboard/signup';
} elseif ($this->id == 18) { } elseif ($this->id == 18) {
$link = 'https://applications.sagepay.com/apply/2C02C252-0F8A-1B84-E10D-CF933EFCAA99'; $link = 'https://applications.sagepay.com/apply/2C02C252-0F8A-1B84-E10D-CF933EFCAA99';
} elseif ($this->id == 20) { } elseif ($this->id == 20 || $this->id == 56) {
$link = 'https://dashboard.stripe.com/account/apikeys'; $link = 'https://dashboard.stripe.com/account/apikeys';
} }
@ -89,17 +89,20 @@ class Gateway extends StaticModel
break; break;
case 7: case 7:
return [ return [
GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true], // Mollie GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true, 'webhooks' => [' ']], // Mollie
GatewayType::BANK_TRANSFER => ['refund' => false, 'token_billing' => true], GatewayType::BANK_TRANSFER => ['refund' => false, 'token_billing' => true, 'webhooks' => [' ']],
GatewayType::KBC => ['refund' => false, 'token_billing' => false], GatewayType::KBC => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']],
GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false], GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']],
GatewayType::IDEAL => ['refund' => false, 'token_billing' => false], GatewayType::IDEAL => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']],
]; ];
case 15: case 15:
return [GatewayType::PAYPAL => ['refund' => true, 'token_billing' => false]]; //Paypal return [
GatewayType::PAYPAL => ['refund' => true, 'token_billing' => false]
]; //Paypal
break; break;
case 20: case 20:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], return [
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true],
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']], GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']],
GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false], GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false],
GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false], GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false],
@ -109,30 +112,41 @@ class Gateway extends StaticModel
GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']]]; GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
];
case 39: case 39:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Checkout return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']]]; //Checkout
break; break;
case 46: case 46:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Paytrace return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Paytrace
case 49: case 49:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], return [
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true]]; //WePay GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true],
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']]
]; //WePay
break; break;
case 50: case 50:
return [ return [
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], //Braintree GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], //Braintree
GatewayType::PAYPAL => ['refund' => true, 'token_billing' => true], GatewayType::PAYPAL => ['refund' => true, 'token_billing' => true],
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true], GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']],
]; ];
break; break;
case 56: case 56:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], return [
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true],
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']], GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']],
GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false], GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false],
GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false], GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false],
GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']]]; //Stripe GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], //Stripe
GatewayType::SEPA => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::PRZELEWY24 => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
];
break; break;
case 57: case 57:
return [ return [
@ -141,12 +155,12 @@ class Gateway extends StaticModel
break; break;
case 52: case 52:
return [ return [
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true] // GoCardless GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']] // GoCardless
]; ];
break; break;
case 58: case 58:
return [ return [
GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false] // Razorpay GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']] // Razorpay
]; ];
break; break;
default: default:

View File

@ -403,10 +403,8 @@ class BaseDriver extends AbstractPaymentDriver
}); });
} }
SystemLogger::dispatch( SystemLogger::dispatch(
$gateway->payment_hash, $gateway->payment_hash,
SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::CATEGORY_GATEWAY_RESPONSE,
@ -620,21 +618,27 @@ class BaseDriver extends AbstractPaymentDriver
{ {
$types = []; $types = [];
// if($type == GatewayType::BANK_TRANSFER && $this->company_gateway->fees_and_limits->{GatewayType::BANK_TRANSFER}->is_enabled)
// {
// $types[] = $type;
// }
// elseif($type == GatewayType::CREDIT_CARD && $this->company_gateway->fees_and_limits->{GatewayType::CREDIT_CARD}->is_enabled)
// {
// $types[] = $type;
// }
$types[] = GatewayType::CREDIT_CARD; $types[] = GatewayType::CREDIT_CARD;
$types[] = GatewayType::BANK_TRANSFER; $types[] = GatewayType::BANK_TRANSFER;
return $types; return $types;
} }
/**
* Generic description handler
*/
public function getDescription(bool $abbreviated = true)
{
if(!$this->payment_hash)
return "";
if($abbreviated)
return \implode(', ', collect($this->payment_hash->invoices())->pluck('invoice_number')->toArray());
return sprintf('%s: %s', ctrans('texts.invoices'), \implode(', ', collect($this->payment_hash->invoices())->pluck('invoice_number')->toArray()));
}
public function disconnect() public function disconnect()
{ {
return true; return true;

View File

@ -88,7 +88,6 @@ class CreditCard
'raw_value' => $request->raw_value, 'raw_value' => $request->raw_value,
'currency' => $request->currency, 'currency' => $request->currency,
'payment_hash' => $request->payment_hash, 'payment_hash' => $request->payment_hash,
'reference' => $request->payment_hash,
'client_id' => $this->checkout->client->id, 'client_id' => $this->checkout->client->id,
]; ];
@ -134,9 +133,10 @@ class CreditCard
private function completePayment($method, PaymentResponseRequest $request) private function completePayment($method, PaymentResponseRequest $request)
{ {
$payment = new Payment($method, $this->checkout->payment_hash->data->currency); $payment = new Payment($method, $this->checkout->payment_hash->data->currency);
$payment->amount = $this->checkout->payment_hash->data->value; $payment->amount = $this->checkout->payment_hash->data->value;
$payment->reference = $this->checkout->payment_hash->data->reference; $payment->reference = $this->checkout->getDescription();
$this->checkout->payment_hash->data = array_merge((array)$this->checkout->payment_hash->data, ['checkout_payment_ref' => $payment]); $this->checkout->payment_hash->data = array_merge((array)$this->checkout->payment_hash->data, ['checkout_payment_ref' => $payment]);
$this->checkout->payment_hash->save(); $this->checkout->payment_hash->save();

View File

@ -243,27 +243,18 @@ class CheckoutComPaymentDriver extends BaseDriver
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total; $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
$invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first();
if ($invoice) {
$description = "Invoice {$invoice->number} for {$amount} for client {$this->client->present()->name()}";
} else {
$description = "Payment with no invoice for amount {$amount} for client {$this->client->present()->name()}";
}
$this->init(); $this->init();
$method = new IdSource($cgt->token); $method = new IdSource($cgt->token);
$payment = new \Checkout\Models\Payments\Payment($method, $this->client->getCurrencyCode()); $payment = new \Checkout\Models\Payments\Payment($method, $this->client->getCurrencyCode());
$payment->amount = $this->convertToCheckoutAmount($amount, $this->client->getCurrencyCode()); $payment->amount = $this->convertToCheckoutAmount($amount, $this->client->getCurrencyCode());
//$payment->reference = $cgt->meta->last4 . '-' . now();
$payment->reference = $invoice->number . '-' . now(); $payment->reference = $invoice->number . '-' . now();
$request = new PaymentResponseRequest(); $request = new PaymentResponseRequest();
$request->setMethod('POST'); $request->setMethod('POST');
$request->request->add(['payment_hash' => $payment_hash->hash]); $request->request->add(['payment_hash' => $payment_hash->hash]);
//$this->setPaymentHash($payment_hash);
try { try {
$response = $this->gateway->payments()->request($payment); $response = $this->gateway->payments()->request($payment);

View File

@ -162,7 +162,7 @@ class ImportCustomers
if(strlen($this->stripe->company_gateway->getConfigField('account_id')) < 1) if(strlen($this->stripe->company_gateway->getConfigField('account_id')) < 1)
throw new StripeConnectFailure('Stripe Connect has not been configured'); throw new StripeConnectFailure('Stripe Connect has not been configured');
$customer = Customer::retrieve($customer_id, $this->stripe_connect_auth); $customer = Customer::retrieve($customer_id, $this->stripe->stripe_connect_auth);
if(!$customer) if(!$customer)
return; return;

View File

@ -89,11 +89,11 @@ class PaymentRepository extends BaseRepository {
if (array_key_exists('credits', $data) && is_array($data['credits']) && count($data['credits']) > 0) { if (array_key_exists('credits', $data) && is_array($data['credits']) && count($data['credits']) > 0) {
$_credit_totals = array_sum(array_column($data['credits'], 'amount')); $_credit_totals = array_sum(array_column($data['credits'], 'amount'));
if ($data['amount'] == $_credit_totals) { // if ($data['amount'] == $_credit_totals) {
$data['amount'] = 0; // $data['amount'] = 0;
} else { // } else {
$client->service()->updatePaidToDate($_credit_totals)->save(); $client->service()->updatePaidToDate($_credit_totals)->save();
} // }
} }
} }
@ -170,11 +170,6 @@ class PaymentRepository extends BaseRepository {
event( new PaymentWasCreated( $payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null) ) ); event( new PaymentWasCreated( $payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null) ) );
} }
// nlog("payment amount = {$payment->amount}");
// nlog("payment applied = {$payment->applied}");
// nlog("invoice totals = {$invoice_totals}");
// nlog("credit totals = {$credit_totals}");
$payment->applied += ($invoice_totals - $credit_totals); //wont work because - check tests $payment->applied += ($invoice_totals - $credit_totals); //wont work because - check tests
// $payment->applied += $invoice_totals; //wont work because - check tests // $payment->applied += $invoice_totals; //wont work because - check tests

View File

@ -73,7 +73,7 @@ class Statement
$state = [ $state = [
'template' => $template->elements([ 'template' => $template->elements([
'client' => $this->entity->client, 'client' => $this->client,
'entity' => $this->entity, 'entity' => $this->entity,
'pdf_variables' => (array)$this->entity->company->settings->pdf_variables, 'pdf_variables' => (array)$this->entity->company->settings->pdf_variables,
'$product' => $this->getDesign()->design->product, '$product' => $this->getDesign()->design->product,
@ -219,7 +219,7 @@ class Statement
*/ */
protected function getInvoices(): Collection protected function getInvoices(): Collection
{ {
return Invoice::where('company_id', $this->client->company->id) return Invoice::where('company_id', $this->client->company_id)
->where('client_id', $this->client->id) ->where('client_id', $this->client->id)
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID]) ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL, Invoice::STATUS_PAID])
->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']])
@ -234,7 +234,8 @@ class Statement
*/ */
protected function getPayments(): Collection protected function getPayments(): Collection
{ {
return Payment::where('company_id', $this->client->company->id) return Payment::with('client.country','invoices')
->where('company_id', $this->client->company_id)
->where('client_id', $this->client->id) ->where('client_id', $this->client->id)
->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED]) ->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])
->whereBetween('date', [$this->options['start_date'], $this->options['end_date']]) ->whereBetween('date', [$this->options['start_date'], $this->options['end_date']])
@ -285,18 +286,15 @@ class Statement
$from = $ranges[0]; $from = $ranges[0];
$to = $ranges[1]; $to = $ranges[1];
$client = Client::where('id', $this->client->id)->first(); $amount = Invoice::where('client_id', $this->client->id)
$amount = Invoice::where('company_id', $this->client->company->id)
->where('client_id', $client->id)
->where('company_id', $this->client->company_id) ->where('company_id', $this->client->company_id)
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
->where('balance', '>', 0) ->where('balance', '>', 0)
->where('is_deleted', 0) ->where('is_deleted', 0)
->whereBetween('date', [$to, $from]) ->whereBetween('due_date', [$to, $from])
->sum('balance'); ->sum('balance');
return Number::formatMoney($amount, $client); return Number::formatMoney($amount, $this->client);
} }
/** /**
@ -328,7 +326,7 @@ class Statement
return $ranges; return $ranges;
case '120+': case '120+':
$ranges[0] = now()->startOfDay()->subDays(120); $ranges[0] = now()->startOfDay()->subDays(120);
$ranges[1] = now()->startOfDay()->subYears(40); $ranges[1] = now()->startOfDay()->subYears(20);
return $ranges; return $ranges;
default: default:
$ranges[0] = now()->startOfDay()->subDays(0); $ranges[0] = now()->startOfDay()->subDays(0);

View File

@ -449,6 +449,8 @@ class InvoiceService
public function fillDefaults() public function fillDefaults()
{ {
$this->invoice->load('client.company');
$settings = $this->invoice->client->getMergedSettings(); $settings = $this->invoice->client->getMergedSettings();
if (! $this->invoice->design_id) if (! $this->invoice->design_id)

View File

@ -58,11 +58,17 @@ class MarkPaid extends AbstractService
$payment->transaction_reference = ctrans('texts.manual_entry'); $payment->transaction_reference = ctrans('texts.manual_entry');
$payment->currency_id = $this->invoice->client->getSetting('currency_id'); $payment->currency_id = $this->invoice->client->getSetting('currency_id');
$payment->is_manual = true; $payment->is_manual = true;
/* Create a payment relationship to the invoice entity */
$payment_type_id = $this->invoice->client->getSetting('payment_type_id');
if((int)$payment_type_id > 0)
$payment->type_id = (int)$payment_type_id;
$payment->save(); $payment->save();
$this->setExchangeRate($payment); $this->setExchangeRate($payment);
/* Create a payment relationship to the invoice entity */
$payment->invoices()->attach($this->invoice->id, [ $payment->invoices()->attach($this->invoice->id, [
'amount' => $payment->amount, 'amount' => $payment->amount,
]); ]);

View File

@ -195,15 +195,15 @@ class Design extends BaseDesign
if ($this->type == self::DELIVERY_NOTE) { if ($this->type == self::DELIVERY_NOTE) {
$elements = [ $elements = [
['element' => 'p', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']], ['element' => 'p', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']],
['element' => 'p', 'content' => $this->entity->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']], ['element' => 'p', 'content' => $this->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']],
['element' => 'p', 'content' => $this->entity->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address1']], ['element' => 'p', 'content' => $this->client->shipping_address1, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address1']],
['element' => 'p', 'content' => $this->entity->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address2']], ['element' => 'p', 'content' => $this->client->shipping_address2, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.shipping_address2']],
['element' => 'p', 'show_empty' => false, 'elements' => [ ['element' => 'p', 'show_empty' => false, 'elements' => [
['element' => 'span', 'content' => "{$this->entity->client->shipping_city} ", 'properties' => ['ref' => 'delivery_note-client.shipping_city']], ['element' => 'span', 'content' => "{$this->client->shipping_city} ", 'properties' => ['ref' => 'delivery_note-client.shipping_city']],
['element' => 'span', 'content' => "{$this->entity->client->shipping_state} ", 'properties' => ['ref' => 'delivery_note-client.shipping_state']], ['element' => 'span', 'content' => "{$this->client->shipping_state} ", 'properties' => ['ref' => 'delivery_note-client.shipping_state']],
['element' => 'span', 'content' => "{$this->entity->client->shipping_postal_code} ", 'properties' => ['ref' => 'delivery_note-client.shipping_postal_code']], ['element' => 'span', 'content' => "{$this->client->shipping_postal_code} ", 'properties' => ['ref' => 'delivery_note-client.shipping_postal_code']],
]], ]],
['element' => 'p', 'content' => optional($this->entity->client->shipping_country)->name, 'show_empty' => false], ['element' => 'p', 'content' => optional($this->client->shipping_country)->name, 'show_empty' => false],
]; ];
if (!is_null($this->context['contact'])) { if (!is_null($this->context['contact'])) {
@ -232,7 +232,7 @@ class Design extends BaseDesign
]], ]],
['element' => 'tr', 'properties' => [], 'elements' => [ ['element' => 'tr', 'properties' => [], 'elements' => [
['element' => 'th', 'properties' => [], 'content' => '$balance_due_label'], ['element' => 'th', 'properties' => [], 'content' => '$balance_due_label'],
['element' => 'th', 'properties' => [], 'content' => Number::formatMoney($this->invoices->sum('balance'), $this->entity->client)], ['element' => 'th', 'properties' => [], 'content' => Number::formatMoney($this->invoices->sum('balance'), $this->client)],
]], ]],
]; ];
} }
@ -363,10 +363,10 @@ class Design extends BaseDesign
$element = ['element' => 'tr', 'elements' => []]; $element = ['element' => 'tr', 'elements' => []];
$element['elements'][] = ['element' => 'td', 'content' => $invoice->number]; $element['elements'][] = ['element' => 'td', 'content' => $invoice->number];
$element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()) ?: '&nbsp;']; $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->due_date, $invoice->client->date_format(), $invoice->client->locale()) ?: '&nbsp;']; $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->due_date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->amount, $invoice->client) ?: '&nbsp;']; $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->amount, $this->client) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->balance, $invoice->client) ?: '&nbsp;']; $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->balance, $this->client) ?: '&nbsp;'];
$tbody[] = $element; $tbody[] = $element;
} }
@ -386,7 +386,7 @@ class Design extends BaseDesign
$outstanding = $this->invoices->sum('balance'); $outstanding = $this->invoices->sum('balance');
return [ return [
['element' => 'p', 'content' => '$outstanding_label: ' . Number::formatMoney($outstanding, $this->entity->client)], ['element' => 'p', 'content' => '$outstanding_label: ' . Number::formatMoney($outstanding, $this->client)],
]; ];
} }
@ -412,9 +412,9 @@ class Design extends BaseDesign
$element = ['element' => 'tr', 'elements' => []]; $element = ['element' => 'tr', 'elements' => []];
$element['elements'][] = ['element' => 'td', 'content' => $invoice->number]; $element['elements'][] = ['element' => 'td', 'content' => $invoice->number];
$element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $payment->client->date_format(), $payment->client->locale()) ?: '&nbsp;']; $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => $payment->type ? $payment->type->name : ctrans('texts.manual_entry')]; $element['elements'][] = ['element' => 'td', 'content' => $payment->type ? $payment->type->name : ctrans('texts.manual_entry')];
$element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->amount, $payment->client) ?: '&nbsp;']; $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->amount, $this->client) ?: '&nbsp;'];
$tbody[] = $element; $tbody[] = $element;
} }
@ -439,7 +439,7 @@ class Design extends BaseDesign
$payment = $this->payments->first(); $payment = $this->payments->first();
return [ return [
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), Number::formatMoney($this->payments->sum('amount'), $payment->client))], ['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), Number::formatMoney($this->payments->sum('amount'), $this->client))],
]; ];
} }
@ -626,7 +626,7 @@ class Design extends BaseDesign
['element' => 'p', 'content' => strtr($_variables['values']['$entity.public_notes'], $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']], ['element' => 'p', 'content' => strtr($_variables['values']['$entity.public_notes'], $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']],
['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column;'], 'elements' => [ ['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column;'], 'elements' => [
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['hidden' => $this->entityVariableCheck('$entity.terms'), 'data-ref' => 'total_table-terms-label', 'style' => 'font-weight: bold; text-align: left; margin-top: 1rem;']], ['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['hidden' => $this->entityVariableCheck('$entity.terms'), 'data-ref' => 'total_table-terms-label', 'style' => 'font-weight: bold; text-align: left; margin-top: 1rem;']],
['element' => 'span', 'content' => strtr($_variables['values']['$entity.terms'], $_variables), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']], ['element' => 'span', 'content' => strtr($_variables['values']['$entity.terms'], $_variables['labels']), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
]], ]],
['element' => 'img', 'properties' => ['style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature', 'id' => 'contact-signature']], ['element' => 'img', 'properties' => ['style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature', 'id' => 'contact-signature']],
['element' => 'div', 'properties' => ['style' => 'margin-top: 1.5rem; display: flex; align-items: flex-start;'], 'elements' => [ ['element' => 'div', 'properties' => ['style' => 'margin-top: 1.5rem; display: flex; align-items: flex-start;'], 'elements' => [

View File

@ -693,6 +693,8 @@ class SubscriptionService
public function convertInvoiceToRecurring($client_id) :RecurringInvoice public function convertInvoiceToRecurring($client_id) :RecurringInvoice
{ {
$client = Client::find($client_id);
$subscription_repo = new SubscriptionRepository(); $subscription_repo = new SubscriptionRepository();
$recurring_invoice = RecurringInvoiceFactory::create($this->subscription->company_id, $this->subscription->user_id); $recurring_invoice = RecurringInvoiceFactory::create($this->subscription->company_id, $this->subscription->user_id);
@ -702,10 +704,23 @@ class SubscriptionService
$recurring_invoice->frequency_id = $this->subscription->frequency_id ?: RecurringInvoice::FREQUENCY_MONTHLY; $recurring_invoice->frequency_id = $this->subscription->frequency_id ?: RecurringInvoice::FREQUENCY_MONTHLY;
$recurring_invoice->date = now(); $recurring_invoice->date = now();
$recurring_invoice->remaining_cycles = -1; $recurring_invoice->remaining_cycles = -1;
$recurring_invoice->auto_bill = $client->getSetting('auto_bill');
$recurring_invoice->auto_bill_enabled = $this->setAutoBillFlag($recurring_invoice->auto_bill);
$recurring_invoice->due_date_days = 'terms';
return $recurring_invoice; return $recurring_invoice;
} }
private function setAutoBillFlag($auto_bill)
{
if ($auto_bill == 'always' || $auto_bill == 'optout') {
return true;
}
return false;
}
/** /**
* Hit a 3rd party API if defined in the subscription * Hit a 3rd party API if defined in the subscription
* *

View File

@ -0,0 +1,290 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace Tests\Feature;
use App\DataMapper\ClientSettings;
use App\Factory\ClientFactory;
use App\Factory\CreditFactory;
use App\Factory\InvoiceFactory;
use App\Factory\InvoiceItemFactory;
use App\Factory\PaymentFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\Payment;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithoutEvents;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\ValidationException;
use Tests\MockAccountData;
use Tests\MockUnitData;
use Tests\TestCase;
/**
* @test
*/
class CreditPaymentTest extends TestCase
{
use MakesHash;
use DatabaseTransactions;
use MockUnitData;
use WithoutEvents;
public function setUp() :void
{
parent::setUp();
Session::start();
$this->faker = \Faker\Factory::create();
Model::reguard();
$this->makeTestData();
$this->withoutExceptionHandling();
$this->withoutMiddleware(
ThrottleRequests::class
);
}
public function testRegularPayment()
{
$invoice = Invoice::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]);
$invoice->line_items = $this->buildLineItems();
$invoice->uses_inclusive_taxes = false;
$invoice->discount = 0;
$invoice->tax_rate1 = 0;
$invoice->tax_name1 = '';
$invoice->tax_rate2 = 0;
$invoice->tax_name2 = '';
$invoice_calc = new InvoiceSum($invoice);
$invoice_calc->build();
$invoice = $invoice_calc->getInvoice();
$invoice->setRelation('client', $this->client);
$invoice->setRelation('company', $this->company);
$invoice->service()->markSent()->save();
$data = [
'amount' => 0,
'client_id' => $this->client->hashed_id,
'invoices' => [
[
'invoice_id' => $invoice->hashed_id,
'amount' => 10,
],
],
'date' => '2019/12/12',
];
$response = false;
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/payments/', $data);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
nlog($e->validator->getMessageBag());
}
$response->assertStatus(200);
$arr = $response->json();
$payment_id = $arr['data']['id'];
$payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first();
$this->assertEquals($payment->amount, 10);
$this->assertEquals($payment->applied, 10);
}
public function testCreditPayments()
{
$invoice = Invoice::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]);
$invoice->line_items = $this->buildLineItems();
$invoice->uses_inclusive_taxes = false;
$invoice->discount = 0;
$invoice->tax_rate1 = 0;
$invoice->tax_name1 = '';
$invoice->tax_rate2 = 0;
$invoice->tax_name2 = '';
$invoice_calc = new InvoiceSum($invoice);
$invoice_calc->build();
$invoice = $invoice_calc->getInvoice();
$invoice->setRelation('client', $this->client);
$invoice->setRelation('company', $this->company);
$invoice->service()->markSent()->save();
$credit = Credit::factory()->create(['user_id' => $this->user->id, 'company_id' => $this->company->id, 'client_id' => $this->client->id]);
$credit->line_items = $this->buildLineItems();
$credit->uses_inclusive_taxes = false;
$credit->discount = 0;
$credit->tax_rate1 = 0;
$credit->tax_name1 = '';
$credit->tax_rate2 = 0;
$credit->tax_name2 = '';
// $invoice->save();
$invoice_calc = new InvoiceSum($credit);
$invoice_calc->build();
$credit = $invoice_calc->getCredit();
$credit->setRelation('client', $this->client);
$credit->setRelation('company', $this->company);
$credit->service()->markSent()->save();
$data = [
'amount' => 0,
'client_id' => $this->client->hashed_id,
'invoices' => [
[
'invoice_id' => $invoice->hashed_id,
'amount' => 10,
],
],
'credits' => [
[
'credit_id' => $credit->hashed_id,
'amount' => 5
]
],
'date' => '2019/12/12',
];
$response = false;
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/payments/', $data);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
nlog($e->validator->getMessageBag());
}
$response->assertStatus(200);
$arr = $response->json();
$payment_id = $arr['data']['id'];
$payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first();
$this->assertEquals($payment->amount, 5);
$this->assertEquals($payment->applied, 5);
}
/*
public function testDoublePaymentTestWithInvalidAmounts()
{
$data = [
'amount' => 15.0,
'client_id' => $this->encodePrimaryKey($client->id),
'invoices' => [
[
'invoice_id' => $this->encodePrimaryKey($this->invoice->id),
'amount' => 10,
],
],
'date' => '2019/12/12',
];
$response = false;
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/payments/', $data);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
\Log::error(print_r($e->validator->getMessageBag(), 1));
}
$response->assertStatus(200);
$arr = $response->json();
$payment_id = $arr['data']['id'];
$payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first();
$this->assertEquals($payment->amount, 15);
$this->assertEquals($payment->applied, 10);
$this->invoice = null;
$this->invoice = InvoiceFactory::create($this->company->id, $this->user->id); //stub the company and user_id
$this->invoice->client_id = $client->id;
$this->invoice->line_items = $this->buildLineItems();
$this->invoice->uses_inclusive_taxes = false;
$this->invoice->save();
$this->invoice_calc = new InvoiceSum($this->invoice);
$this->invoice_calc->build();
$this->invoice = $this->invoice_calc->getInvoice();
$this->invoice->save();
$this->invoice->service()->markSent()->save();
$data = [
'amount' => 15.0,
'client_id' => $this->encodePrimaryKey($client->id),
'invoices' => [
[
'invoice_id' => $this->encodePrimaryKey($this->invoice->id),
'amount' => 10,
],
],
'date' => '2019/12/12',
];
$response = false;
try {
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->put('/api/v1/payments/'.$this->encodePrimaryKey($payment->id), $data);
} catch (ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(), 1);
$this->assertTrue(array_key_exists('invoices', $message));
}
}
*/
}

View File

@ -185,7 +185,7 @@ class RecurringExpenseApiTest extends TestCase
])->post('/api/v1/recurring_expenses/bulk?action=start', $data); ])->post('/api/v1/recurring_expenses/bulk?action=start', $data);
$arr = $response->json(); $arr = $response->json();
nlog($arr);
$this->assertEquals(RecurringInvoice::STATUS_ACTIVE, $arr['data'][0]['status_id']); $this->assertEquals(RecurringInvoice::STATUS_ACTIVE, $arr['data'][0]['status_id']);
} }
@ -207,7 +207,7 @@ nlog($arr);
])->post('/api/v1/recurring_expenses/bulk?action=stop', $data); ])->post('/api/v1/recurring_expenses/bulk?action=stop', $data);
$arr = $response->json(); $arr = $response->json();
nlog($arr);
$this->assertEquals(RecurringInvoice::STATUS_PAUSED, $arr['data'][0]['status_id']); $this->assertEquals(RecurringInvoice::STATUS_PAUSED, $arr['data'][0]['status_id']);
} }

View File

@ -311,9 +311,9 @@ class AuthorizeTest extends TestCase
$response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX); $response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX);
// nlog($response); // nlog($response);
nlog($response->getTransactionResponse()->getMessages() !== null); // nlog($response->getTransactionResponse()->getMessages() !== null);
nlog($response->getTransactionResponse()->getMessages()); // nlog($response->getTransactionResponse()->getMessages());
nlog($response->getTransactionResponse()->getMessages()[0]); // nlog($response->getTransactionResponse()->getMessages()[0]);
//nlog($response->getTransactionResponse()->getMessages()[0]->getCode()); //nlog($response->getTransactionResponse()->getMessages()[0]->getCode());
$code = ''; $code = '';

View File

@ -11,10 +11,14 @@
namespace Tests; namespace Tests;
use App\DataMapper\CompanySettings;
use App\DataMapper\DefaultSettings;
use App\Factory\InvoiceItemFactory;
use App\Models\Account; use App\Models\Account;
use App\Models\Client; use App\Models\Client;
use App\Models\ClientContact; use App\Models\ClientContact;
use App\Models\Company; use App\Models\Company;
use App\Models\CompanyToken;
use App\Models\User; use App\Models\User;
/** /**
* Class MockUnitData. * Class MockUnitData.
@ -33,6 +37,8 @@ trait MockUnitData
public $primary_contact; public $primary_contact;
public $token;
public function makeTestData() public function makeTestData()
{ {
@ -49,6 +55,39 @@ trait MockUnitData
'account_id' => $this->account->id 'account_id' => $this->account->id
]); ]);
$userPermissions = collect([
'view_invoice',
'view_client',
'edit_client',
'edit_invoice',
'create_invoice',
'create_client',
]);
$userSettings = DefaultSettings::userSettings();
$this->user->companies()->attach($this->company->id, [
'account_id' => $this->account->id,
'is_owner' => 1,
'is_admin' => 1,
'notifications' => CompanySettings::notificationDefaults(),
'permissions' => $userPermissions->toJson(),
'settings' => json_encode($userSettings),
'is_locked' => 0,
]);
$this->token = \Illuminate\Support\Str::random(64);
$company_token = new CompanyToken;
$company_token->user_id = $this->user->id;
$company_token->company_id = $this->company->id;
$company_token->account_id = $this->account->id;
$company_token->name = 'test token';
$company_token->token = $this->token;
$company_token->is_system = true;
$company_token->save();
$this->client = Client::factory()->create([ $this->client = Client::factory()->create([
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'company_id' => $this->company->id 'company_id' => $this->company->id
@ -68,4 +107,17 @@ trait MockUnitData
]); ]);
} }
public function buildLineItems()
{
$line_items = [];
$item = InvoiceItemFactory::create();
$item->quantity = 1;
$item->cost = 10;
$line_items[] = $item;
return $line_items;
}
} }

View File

@ -275,7 +275,9 @@ class InvoiceInclusiveTest extends TestCase
$this->assertEquals($this->invoice_calc->getSubTotal(), 19); $this->assertEquals($this->invoice_calc->getSubTotal(), 19);
$this->assertEquals($this->invoice_calc->getTotalDiscount(), 0.95); $this->assertEquals($this->invoice_calc->getTotalDiscount(), 0.95);
$this->assertEquals($this->invoice_calc->getTotalTaxes(), 4.92); $this->assertEquals($this->invoice_calc->getTotalTaxes(), 4.92);
nlog($this->invoice_calc->getTaxMap());
// nlog($this->invoice_calc->getTaxMap());
$this->assertEquals(count($this->invoice_calc->getTaxMap()), 1); $this->assertEquals(count($this->invoice_calc->getTaxMap()), 1);
$this->assertEquals($this->invoice_calc->getTotal(), 18.05); $this->assertEquals($this->invoice_calc->getTotal(), 18.05);
$this->assertEquals($this->invoice_calc->getBalance(), 18.05); $this->assertEquals($this->invoice_calc->getBalance(), 18.05);