Merge branch 'v5-develop' into v5-stable

This commit is contained in:
David Bomba 2023-07-23 17:50:16 +10:00
commit 319f2e78dc
113 changed files with 368652 additions and 367870 deletions

View File

@ -1 +1 @@
5.6.19 5.6.21

View File

@ -24,7 +24,6 @@ use App\Transformers\ActivityTransformer;
class ActivityExport extends BaseExport class ActivityExport extends BaseExport
{ {
private Company $company;
private $entity_transformer; private $entity_transformer;

View File

@ -13,14 +13,14 @@ namespace App\Export\CSV;
use App\Utils\Number; use App\Utils\Number;
use App\Models\Client; use App\Models\Client;
use App\Models\Company;
use App\Models\Expense; use App\Models\Expense;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\GatewayType;
use App\Models\Payment; use App\Models\Payment;
use League\Fractal\Manager; use League\Fractal\Manager;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Transformers\ClientTransformer; use App\Transformers\TaskTransformer;
use App\Transformers\PaymentTransformer; use App\Transformers\PaymentTransformer;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use League\Fractal\Serializer\ArraySerializer; use League\Fractal\Serializer\ArraySerializer;
@ -29,6 +29,8 @@ class BaseExport
{ {
use MakesHash; use MakesHash;
public Company $company;
public array $input; public array $input;
public string $date_key = ''; public string $date_key = '';
@ -136,6 +138,35 @@ class BaseExport
"user" => "invoice.user_id", "user" => "invoice.user_id",
]; ];
protected array $recurring_invoice_report_keys = [
"invoice_number" => "recurring_invoice.number",
"amount" => "recurring_invoice.amount",
"balance" => "recurring_invoice.balance",
"paid_to_date" => "recurring_invoice.paid_to_date",
"po_number" => "recurring_invoice.po_number",
"date" => "recurring_invoice.date",
"due_date" => "recurring_invoice.due_date",
"terms" => "recurring_invoice.terms",
"footer" => "recurring_invoice.footer",
"status" => "recurring_invoice.status",
"public_notes" => "recurring_invoice.public_notes",
"private_notes" => "recurring_invoice.private_notes",
"uses_inclusive_taxes" => "recurring_invoice.uses_inclusive_taxes",
"is_amount_discount" => "recurring_invoice.is_amount_discount",
"partial" => "recurring_invoice.partial",
"partial_due_date" => "recurring_invoice.partial_due_date",
"surcharge1" => "recurring_invoice.custom_surcharge1",
"surcharge2" => "recurring_invoice.custom_surcharge2",
"surcharge3" => "recurring_invoice.custom_surcharge3",
"surcharge4" => "recurring_invoice.custom_surcharge4",
"exchange_rate" => "recurring_invoice.exchange_rate",
"tax_amount" => "recurring_invoice.total_taxes",
"assigned_user" => "recurring_invoice.assigned_user_id",
"user" => "recurring_invoice.user_id",
"frequency_id" => "recurring_invoice.frequency_id",
"next_send_date" => "recurring_invoice.next_send_date"
];
protected array $purchase_order_report_keys = [ protected array $purchase_order_report_keys = [
'amount' => 'purchase_order.amount', 'amount' => 'purchase_order.amount',
'balance' => 'purchase_order.balance', 'balance' => 'purchase_order.balance',
@ -193,13 +224,17 @@ class BaseExport
]; ];
protected array $quote_report_keys = [ protected array $quote_report_keys = [
"quote_number" => "quote.number", 'custom_value1' => 'quote.custom_value1',
'custom_value2' => 'quote.custom_value2',
'custom_value3' => 'quote.custom_value3',
'custom_value4' => 'quote.custom_value4',
"number" => "quote.number",
"amount" => "quote.amount", "amount" => "quote.amount",
"balance" => "quote.balance", "balance" => "quote.balance",
"paid_to_date" => "quote.paid_to_date", "paid_to_date" => "quote.paid_to_date",
"po_number" => "quote.po_number", "po_number" => "quote.po_number",
"date" => "quote.date", "date" => "quote.date",
"due_date" => "quote.due_date", "valid_until" => "quote.due_date",
"terms" => "quote.terms", "terms" => "quote.terms",
"footer" => "quote.footer", "footer" => "quote.footer",
"status" => "quote.status", "status" => "quote.status",
@ -314,8 +349,6 @@ class BaseExport
'custom_value4' => 'task.custom_value4', 'custom_value4' => 'task.custom_value4',
'status' => 'task.status_id', 'status' => 'task.status_id',
'project' => 'task.project_id', 'project' => 'task.project_id',
'invoice' => 'task.invoice_id',
'client' => 'task.client_id',
]; ];
protected function filterByClients($query) protected function filterByClients($query)
@ -347,8 +380,11 @@ class BaseExport
'vendor' => $value = $this->resolveVendorKey($parts[1], $entity, $transformer), 'vendor' => $value = $this->resolveVendorKey($parts[1], $entity, $transformer),
'vendor_contact' => $value = $this->resolveVendorContactKey($parts[1], $entity, $transformer), 'vendor_contact' => $value = $this->resolveVendorContactKey($parts[1], $entity, $transformer),
'invoice' => $value = $this->resolveInvoiceKey($parts[1], $entity, $transformer), 'invoice' => $value = $this->resolveInvoiceKey($parts[1], $entity, $transformer),
'recurring_invoice' => $value = $this->resolveInvoiceKey($parts[1], $entity, $transformer),
'quote' => $value = $this->resolveQuoteKey($parts[1], $entity, $transformer),
'purchase_order' => $value = $this->resolvePurchaseOrderKey($parts[1], $entity, $transformer), 'purchase_order' => $value = $this->resolvePurchaseOrderKey($parts[1], $entity, $transformer),
'payment' => $value = $this->resolvePaymentKey($parts[1], $entity, $transformer), 'payment' => $value = $this->resolvePaymentKey($parts[1], $entity, $transformer),
'task' => $value = $this->resolveTaskKey($parts[1], $entity, $transformer),
default => $value = '' default => $value = ''
}; };
@ -414,6 +450,22 @@ class BaseExport
} }
private function resolveTaskKey($column, $entity, $transformer)
{
nlog("searching for {$column}");
$transformed_entity = $transformer->transform($entity);
if(array_key_exists($column, $transformed_entity)) {
return $transformed_entity[$column];
}
return '';
}
private function resolveVendorKey($column, $entity, $transformer) private function resolveVendorKey($column, $entity, $transformer)
{ {
@ -511,6 +563,20 @@ class BaseExport
return ''; return '';
} }
private function resolveQuoteKey($column, $entity, $transformer)
{
nlog("searching for {$column}");
$transformed_entity = $transformer->transform($entity);
if(array_key_exists($column, $transformed_entity)) {
return $transformed_entity[$column];
}
return '';
}
private function resolveInvoiceKey($column, $entity, $transformer) private function resolveInvoiceKey($column, $entity, $transformer)
{ {
nlog("searching for {$column}"); nlog("searching for {$column}");
@ -537,7 +603,23 @@ class BaseExport
} }
$transformed_invoice = $transformer->transform($entity); if($transformer instanceof TaskTransformer) {
$transformed_invoice = $transformer->includeInvoice($entity);
if(!$transformed_invoice)
return '';
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
$transformed_invoice = $manager->createData($transformed_invoice)->toArray();
}
if(array_key_exists($column, $transformed_invoice)) {
return $transformed_invoice[$column];
} elseif (array_key_exists(str_replace("invoice.", "", $column), $transformed_invoice)) {
return $transformed_invoice[$column];
}
if($column == 'status') if($column == 'status')
return $entity->stringStatus($entity->status_id); return $entity->stringStatus($entity->status_id);
@ -707,8 +789,27 @@ class BaseExport
$this->end_date = now()->startOfDay()->format('Y-m-d'); $this->end_date = now()->startOfDay()->format('Y-m-d');
return $query->whereBetween($this->date_key, [now()->subDays(365), now()])->orderBy($this->date_key, 'ASC'); return $query->whereBetween($this->date_key, [now()->subDays(365), now()])->orderBy($this->date_key, 'ASC');
case 'this_year': case 'this_year':
$this->start_date = now()->startOfYear()->format('Y-m-d');
$this->end_date = now()->format('Y-m-d'); $first_month_of_year = $this->company->getSetting('first_month_of_year') ?? 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
if(now()->lt($fin_year_start))
$fin_year_start->subYearNoOverflow();
$this->start_date = $fin_year_start->format('Y-m-d');
$this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d');
return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
case 'last_year':
$first_month_of_year = $this->company->getSetting('first_month_of_year') ?? 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
$fin_year_start->subYearNoOverflow();
if(now()->subYear()->lt($fin_year_start))
$fin_year_start->subYearNoOverflow();
$this->start_date = $fin_year_start->format('Y-m-d');
$this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d');
return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC'); return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
case 'custom': case 'custom':
$this->start_date = $custom_start_date->format('Y-m-d'); $this->start_date = $custom_start_date->format('Y-m-d');
@ -743,6 +844,11 @@ class BaseExport
$key = array_search($value, $this->invoice_report_keys); $key = array_search($value, $this->invoice_report_keys);
} }
if(!$key) {
$prefix = ctrans('texts.recurring_invoice')." ";
$key = array_search($value, $this->recurring_invoice_report_keys);
}
if(!$key) { if(!$key) {
$prefix = ctrans('texts.payment')." "; $prefix = ctrans('texts.payment')." ";
$key = array_search($value, $this->payment_report_keys); $key = array_search($value, $this->payment_report_keys);
@ -790,6 +896,7 @@ class BaseExport
$key = str_replace('item.', '', $key); $key = str_replace('item.', '', $key);
$key = str_replace('recurring_invoice.', '', $key); $key = str_replace('recurring_invoice.', '', $key);
$key = str_replace('purchase_order.', '', $key);
$key = str_replace('invoice.', '', $key); $key = str_replace('invoice.', '', $key);
$key = str_replace('quote.', '', $key); $key = str_replace('quote.', '', $key);
$key = str_replace('credit.', '', $key); $key = str_replace('credit.', '', $key);
@ -800,9 +907,18 @@ class BaseExport
$key = str_replace('payment.', '', $key); $key = str_replace('payment.', '', $key);
$key = str_replace('expense.', '', $key); $key = str_replace('expense.', '', $key);
if(in_array($key, ['quote1','quote2','quote3','quote4','credit1','credit2','credit3','credit4','purchase_order1','purchase_order2','purchase_order3','purchase_order4']))
{
$number = substr($key, -1);
$header[] = ctrans('texts.item') . " ". ctrans("texts.custom_value{$number}");
}
else
{
$header[] = "{$prefix}" . ctrans("texts.{$key}"); $header[] = "{$prefix}" . ctrans("texts.{$key}");
} }
// nlog($header); }
// nlog($header);
return $header; return $header;
} }

View File

@ -22,8 +22,6 @@ use League\Csv\Writer;
class ClientExport extends BaseExport class ClientExport extends BaseExport
{ {
private $company;
private $client_transformer; private $client_transformer;
private $contact_transformer; private $contact_transformer;
@ -172,8 +170,8 @@ class ClientExport extends BaseExport
$entity['shipping_country'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : ''; $entity['shipping_country'] = $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : '';
} }
if (in_array('client.currency', $this->input['report_keys'])) { if (in_array('client.currency_id', $this->input['report_keys'])) {
$entity['currency'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code; $entity['client.currency_id'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
} }
if (in_array('client.industry_id', $this->input['report_keys'])) { if (in_array('client.industry_id', $this->input['report_keys'])) {

View File

@ -23,7 +23,6 @@ use League\Csv\Writer;
class ContactExport extends BaseExport class ContactExport extends BaseExport
{ {
private Company $company;
private ClientTransformer $client_transformer; private ClientTransformer $client_transformer;

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class CreditExport extends BaseExport class CreditExport extends BaseExport
{ {
private Company $company;
private CreditTransformer $credit_transformer; private CreditTransformer $credit_transformer;

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class DocumentExport extends BaseExport class DocumentExport extends BaseExport
{ {
private Company $company;
private $entity_transformer; private $entity_transformer;

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class ExpenseExport extends BaseExport class ExpenseExport extends BaseExport
{ {
private Company $company;
private $expense_transformer; private $expense_transformer;

View File

@ -23,8 +23,6 @@ use App\Transformers\InvoiceTransformer;
class InvoiceExport extends BaseExport class InvoiceExport extends BaseExport
{ {
private Company $company;
private $invoice_transformer; private $invoice_transformer;
public string $date_key = 'date'; public string $date_key = 'date';

View File

@ -22,7 +22,6 @@ use League\Csv\Writer;
class InvoiceItemExport extends BaseExport class InvoiceItemExport extends BaseExport
{ {
private Company $company;
private $invoice_transformer; private $invoice_transformer;

View File

@ -21,8 +21,6 @@ use League\Csv\Writer;
class PaymentExport extends BaseExport class PaymentExport extends BaseExport
{ {
private Company $company;
private $entity_transformer; private $entity_transformer;
public string $date_key = 'date'; public string $date_key = 'date';

View File

@ -22,8 +22,6 @@ use League\Csv\Writer;
class ProductExport extends BaseExport class ProductExport extends BaseExport
{ {
private Company $company;
private $entity_transformer; private $entity_transformer;
public string $date_key = 'created_at'; public string $date_key = 'created_at';

View File

@ -23,8 +23,6 @@ use League\Csv\Writer;
class ProductSalesExport extends BaseExport class ProductSalesExport extends BaseExport
{ {
private Company $company;
public string $date_key = 'created_at'; public string $date_key = 'created_at';
protected Collection $products; protected Collection $products;

View File

@ -22,7 +22,6 @@ use League\Csv\Writer;
class PurchaseOrderExport extends BaseExport class PurchaseOrderExport extends BaseExport
{ {
private Company $company;
private $purchase_order_transformer; private $purchase_order_transformer;
@ -31,39 +30,39 @@ class PurchaseOrderExport extends BaseExport
public Writer $csv; public Writer $csv;
public array $entity_keys = [ public array $entity_keys = [
'amount' => 'amount', 'amount' => 'purchase_order.amount',
'balance' => 'balance', 'balance' => 'purchase_order.balance',
'vendor' => 'vendor_id', 'vendor' => 'purchase_order.vendor_id',
'custom_surcharge1' => 'custom_surcharge1', // 'custom_surcharge1' => 'purchase_order.custom_surcharge1',
'custom_surcharge2' => 'custom_surcharge2', // 'custom_surcharge2' => 'purchase_order.custom_surcharge2',
'custom_surcharge3' => 'custom_surcharge3', // 'custom_surcharge3' => 'purchase_order.custom_surcharge3',
'custom_surcharge4' => 'custom_surcharge4', // 'custom_surcharge4' => 'purchase_order.custom_surcharge4',
'custom_value1' => 'custom_value1', 'custom_value1' => 'purchase_order.custom_value1',
'custom_value2' => 'custom_value2', 'custom_value2' => 'purchase_order.custom_value2',
'custom_value3' => 'custom_value3', 'custom_value3' => 'purchase_order.custom_value3',
'custom_value4' => 'custom_value4', 'custom_value4' => 'purchase_order.custom_value4',
'date' => 'date', 'date' => 'purchase_order.date',
'discount' => 'discount', 'discount' => 'purchase_order.discount',
'due_date' => 'due_date', 'due_date' => 'purchase_order.due_date',
'exchange_rate' => 'exchange_rate', 'exchange_rate' => 'purchase_order.exchange_rate',
'footer' => 'footer', 'footer' => 'purchase_order.footer',
'number' => 'number', 'number' => 'purchase_order.number',
'paid_to_date' => 'paid_to_date', 'paid_to_date' => 'purchase_order.paid_to_date',
'partial' => 'partial', 'partial' => 'purchase_order.partial',
'partial_due_date' => 'partial_due_date', 'partial_due_date' => 'purchase_order.partial_due_date',
'po_number' => 'po_number', 'po_number' => 'purchase_order.po_number',
'private_notes' => 'private_notes', 'private_notes' => 'purchase_order.private_notes',
'public_notes' => 'public_notes', 'public_notes' => 'purchase_order.public_notes',
'status' => 'status_id', 'status' => 'purchase_order.status_id',
'tax_name1' => 'tax_name1', 'tax_name1' => 'purchase_order.tax_name1',
'tax_name2' => 'tax_name2', 'tax_name2' => 'purchase_order.tax_name2',
'tax_name3' => 'tax_name3', 'tax_name3' => 'purchase_order.tax_name3',
'tax_rate1' => 'tax_rate1', 'tax_rate1' => 'purchase_order.tax_rate1',
'tax_rate2' => 'tax_rate2', 'tax_rate2' => 'purchase_order.tax_rate2',
'tax_rate3' => 'tax_rate3', 'tax_rate3' => 'purchase_order.tax_rate3',
'terms' => 'terms', 'terms' => 'purchase_order.terms',
'total_taxes' => 'total_taxes', 'total_taxes' => 'purchase_order.total_taxes',
'currency_id' => 'currency_id', 'currency_id' => 'purchase_order.currency_id',
]; ];
private array $decorate_keys = [ private array $decorate_keys = [
@ -130,7 +129,7 @@ class PurchaseOrderExport extends BaseExport
$keyval = array_search($key, $this->entity_keys); $keyval = array_search($key, $this->entity_keys);
if(!$keyval) { if(!$keyval) {
$keyval = array_search(str_replace("invoice.", "", $key), $this->entity_keys) ?? $key; $keyval = array_search(str_replace("purchase_order.", "", $key), $this->entity_keys) ?? $key;
} }
if(!$keyval) { if(!$keyval) {

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class PurchaseOrderItemExport extends BaseExport class PurchaseOrderItemExport extends BaseExport
{ {
private Company $company;
private $purchase_order_transformer; private $purchase_order_transformer;
@ -37,10 +36,10 @@ class PurchaseOrderItemExport extends BaseExport
'vendor' => 'vendor_id', 'vendor' => 'vendor_id',
'vendor_number' => 'vendor.number', 'vendor_number' => 'vendor.number',
'vendor_id_number' => 'vendor.id_number', 'vendor_id_number' => 'vendor.id_number',
'custom_surcharge1' => 'custom_surcharge1', // 'custom_surcharge1' => 'custom_surcharge1',
'custom_surcharge2' => 'custom_surcharge2', // 'custom_surcharge2' => 'custom_surcharge2',
'custom_surcharge3' => 'custom_surcharge3', // 'custom_surcharge3' => 'custom_surcharge3',
'custom_surcharge4' => 'custom_surcharge4', // 'custom_surcharge4' => 'custom_surcharge4',
// 'custom_value1' => 'custom_value1', // 'custom_value1' => 'custom_value1',
// 'custom_value2' => 'custom_value2', // 'custom_value2' => 'custom_value2',
// 'custom_value3' => 'custom_value3', // 'custom_value3' => 'custom_value3',
@ -82,10 +81,10 @@ class PurchaseOrderItemExport extends BaseExport
'tax_name3' => 'item.tax_name3', 'tax_name3' => 'item.tax_name3',
'line_total' => 'item.line_total', 'line_total' => 'item.line_total',
'gross_line_total' => 'item.gross_line_total', 'gross_line_total' => 'item.gross_line_total',
// 'invoice1' => 'item.custom_value1', 'purchase_order1' => 'item.custom_value1',
// 'invoice2' => 'item.custom_value2', 'purchase_order2' => 'item.custom_value2',
// 'invoice3' => 'item.custom_value3', 'purchase_order3' => 'item.custom_value3',
// 'invoice4' => 'item.custom_value4', 'purchase_order4' => 'item.custom_value4',
'tax_category' => 'item.tax_id', 'tax_category' => 'item.tax_id',
'type' => 'item.type_id', 'type' => 'item.type_id',
]; ];
@ -139,7 +138,7 @@ class PurchaseOrderItemExport extends BaseExport
private function iterateItems(PurchaseOrder $purchase_order) private function iterateItems(PurchaseOrder $purchase_order)
{ {
$transformed_invoice = $this->buildRow($purchase_order); $transformed_purchase_order = $this->buildRow($purchase_order);
$transformed_items = []; $transformed_items = [];
@ -154,7 +153,7 @@ class PurchaseOrderItemExport extends BaseExport
$keyval = $key; $keyval = $key;
$keyval = str_replace("custom_value", "invoice", $key); $keyval = str_replace("custom_value", "purchase_order", $key);
if($key == 'type_id') { if($key == 'type_id') {
$keyval = 'type'; $keyval = 'type';
@ -184,7 +183,7 @@ class PurchaseOrderItemExport extends BaseExport
} }
} }
$transformed_items = array_merge($transformed_invoice, $item_array); $transformed_items = array_merge($transformed_purchase_order, $item_array);
$entity = $this->decorateAdvancedFields($purchase_order, $transformed_items); $entity = $this->decorateAdvancedFields($purchase_order, $transformed_items);
$this->csv->insertOne($entity); $this->csv->insertOne($entity);
@ -193,7 +192,7 @@ class PurchaseOrderItemExport extends BaseExport
private function buildRow(PurchaseOrder $purchase_order) :array private function buildRow(PurchaseOrder $purchase_order) :array
{ {
$transformed_invoice = $this->purchase_order_transformer->transform($purchase_order); $transformed_purchase_order = $this->purchase_order_transformer->transform($purchase_order);
$entity = []; $entity = [];
@ -201,17 +200,17 @@ class PurchaseOrderItemExport extends BaseExport
$keyval = array_search($key, $this->entity_keys); $keyval = array_search($key, $this->entity_keys);
if(!$keyval) { if(!$keyval) {
$keyval = array_search(str_replace("invoice.", "", $key), $this->entity_keys) ?? $key; $keyval = array_search(str_replace("purchase_order.", "", $key), $this->entity_keys) ?? $key;
} }
if(!$keyval) { if(!$keyval) {
$keyval = $key; $keyval = $key;
} }
if (array_key_exists($key, $transformed_invoice)) { if (array_key_exists($key, $transformed_purchase_order)) {
$entity[$keyval] = $transformed_invoice[$key]; $entity[$keyval] = $transformed_purchase_order[$key];
} elseif (array_key_exists($keyval, $transformed_invoice)) { } elseif (array_key_exists($keyval, $transformed_purchase_order)) {
$entity[$keyval] = $transformed_invoice[$keyval]; $entity[$keyval] = $transformed_purchase_order[$keyval];
} else { } else {
$entity[$keyval] = $this->resolveKey($keyval, $purchase_order, $this->purchase_order_transformer); $entity[$keyval] = $this->resolveKey($keyval, $purchase_order, $this->purchase_order_transformer);
} }

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class QuoteExport extends BaseExport class QuoteExport extends BaseExport
{ {
private Company $company;
private $quote_transformer; private $quote_transformer;
@ -43,7 +42,7 @@ class QuoteExport extends BaseExport
'custom_value4' => 'custom_value4', 'custom_value4' => 'custom_value4',
'date' => 'date', 'date' => 'date',
'discount' => 'discount', 'discount' => 'discount',
'due_date' => 'due_date', 'valid_until' => 'due_date',
'exchange_rate' => 'exchange_rate', 'exchange_rate' => 'exchange_rate',
'footer' => 'footer', 'footer' => 'footer',
'number' => 'number', 'number' => 'number',
@ -115,17 +114,28 @@ class QuoteExport extends BaseExport
private function buildRow(Quote $quote) :array private function buildRow(Quote $quote) :array
{ {
$transformed_quote = $this->quote_transformer->transform($quote); $transformed_entity = $this->quote_transformer->transform($quote);
$entity = []; $entity = [];
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys); $keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_quote)) { if(!$keyval) {
$entity[$keyval] = $transformed_quote[$key]; $keyval = array_search(str_replace("invoice.", "", $key), $this->entity_keys) ?? $key;
} else { }
$entity[$keyval] = '';
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} elseif (array_key_exists($keyval, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $quote, $this->quote_transformer);
} }
} }

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class QuoteItemExport extends BaseExport class QuoteItemExport extends BaseExport
{ {
private Company $company;
private $quote_transformer; private $quote_transformer;
@ -63,10 +62,11 @@ class QuoteItemExport extends BaseExport
'terms' => 'terms', 'terms' => 'terms',
'total_taxes' => 'total_taxes', 'total_taxes' => 'total_taxes',
'currency' => 'currency_id', 'currency' => 'currency_id',
'qty' => 'item.quantity', 'quantity' => 'item.quantity',
'unit_cost' => 'item.cost', 'cost' => 'item.cost',
'product_key' => 'item.product_key', 'product_key' => 'item.product_key',
'cost' => 'item.product_cost', 'buy_price' => 'item.product_cost',
'cost' => 'item.cost',
'notes' => 'item.notes', 'notes' => 'item.notes',
'discount' => 'item.discount', 'discount' => 'item.discount',
'is_amount_discount' => 'item.is_amount_discount', 'is_amount_discount' => 'item.is_amount_discount',
@ -77,11 +77,13 @@ class QuoteItemExport extends BaseExport
'tax_name2' => 'item.tax_name2', 'tax_name2' => 'item.tax_name2',
'tax_name3' => 'item.tax_name3', 'tax_name3' => 'item.tax_name3',
'line_total' => 'item.line_total', 'line_total' => 'item.line_total',
// 'gross_line_total' => 'item.gross_line_total', 'gross_line_total' => 'item.gross_line_total',
'custom_value1' => 'item.custom_value1', 'quote1' => 'item.custom_value1',
'custom_value2' => 'item.custom_value2', 'quote2' => 'item.custom_value2',
'custom_value3' => 'item.custom_value3', 'quote3' => 'item.custom_value3',
'custom_value4' => 'item.custom_value4', 'quote4' => 'item.custom_value4',
'tax_category' => 'item.tax_id',
'type' => 'item.type_id',
]; ];
private array $decorate_keys = [ private array $decorate_keys = [
@ -135,25 +137,44 @@ class QuoteItemExport extends BaseExport
$transformed_items = []; $transformed_items = [];
$transformed_items = [];
foreach ($quote->line_items as $item) { foreach ($quote->line_items as $item) {
$item_array = []; $item_array = [];
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) { //items iterator produces item array
if (str_contains($key, 'item.')) {
$key = str_replace('item.', '', $key); if (str_contains($key, "item.")) {
$item_array[$key] = $item->{$key};
$key = str_replace("item.", "", $key);
$keyval = $key;
$keyval = str_replace("custom_value", "quote", $key);
if($key == 'type_id')
$keyval = 'type';
if($key == 'tax_id')
$keyval = 'tax_category';
if (property_exists($item, $key)) {
$item_array[$keyval] = $item->{$key};
} else {
$item_array[$keyval] = '';
}
} }
} }
$entity = []; $entity = [];
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) { //create an array of report keys only
$keyval = array_search($key, $this->entity_keys); $keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_items)) { if (array_key_exists($key, $transformed_items)) {
$entity[$keyval] = $transformed_items[$key]; $entity[$keyval] = $transformed_items[$key];
} else { } else {
$entity[$keyval] = ''; $entity[$keyval] = "";
} }
} }
@ -173,16 +194,26 @@ class QuoteItemExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys); $keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("quote.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_quote)) { if (array_key_exists($key, $transformed_quote)) {
$entity[$keyval] = $transformed_quote[$key]; $entity[$keyval] = $transformed_quote[$key];
} else { } elseif (array_key_exists($keyval, $transformed_quote)) {
$entity[$keyval] = ''; $entity[$keyval] = $transformed_quote[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $quote, $this->quote_transformer);
} }
} }
return $this->decorateAdvancedFields($quote, $entity); return $this->decorateAdvancedFields($quote, $entity);
} }
private function decorateAdvancedFields(Quote $quote, array $entity) :array private function decorateAdvancedFields(Quote $quote, array $entity) :array
{ {
if (in_array('currency_id', $this->input['report_keys'])) { if (in_array('currency_id', $this->input['report_keys'])) {

View File

@ -21,7 +21,6 @@ use League\Csv\Writer;
class RecurringInvoiceExport extends BaseExport class RecurringInvoiceExport extends BaseExport
{ {
private Company $company;
private $invoice_transformer; private $invoice_transformer;
@ -33,10 +32,10 @@ class RecurringInvoiceExport extends BaseExport
'amount' => 'amount', 'amount' => 'amount',
'balance' => 'balance', 'balance' => 'balance',
'client' => 'client_id', 'client' => 'client_id',
'custom_surcharge1' => 'custom_surcharge1', // 'custom_surcharge1' => 'custom_surcharge1',
'custom_surcharge2' => 'custom_surcharge2', // 'custom_surcharge2' => 'custom_surcharge2',
'custom_surcharge3' => 'custom_surcharge3', // 'custom_surcharge3' => 'custom_surcharge3',
'custom_surcharge4' => 'custom_surcharge4', // 'custom_surcharge4' => 'custom_surcharge4',
'custom_value1' => 'custom_value1', 'custom_value1' => 'custom_value1',
'custom_value2' => 'custom_value2', 'custom_value2' => 'custom_value2',
'custom_value3' => 'custom_value3', 'custom_value3' => 'custom_value3',
@ -66,7 +65,8 @@ class RecurringInvoiceExport extends BaseExport
'currency' => 'currency_id', 'currency' => 'currency_id',
'vendor' => 'vendor_id', 'vendor' => 'vendor_id',
'project' => 'project_id', 'project' => 'project_id',
'frequency' => 'frequency_id' 'frequency_id' => 'frequency_id',
'next_send_date' => 'next_send_date'
]; ];
private array $decorate_keys = [ private array $decorate_keys = [
@ -127,11 +127,22 @@ class RecurringInvoiceExport extends BaseExport
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys); $keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("recurring_invoice.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_invoice)) { if (array_key_exists($key, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$key]; $entity[$keyval] = $transformed_invoice[$key];
} elseif (array_key_exists($keyval, $transformed_invoice)) {
$entity[$keyval] = $transformed_invoice[$keyval];
} else { } else {
$entity[$keyval] = ''; $entity[$keyval] = $this->resolveKey($keyval, $invoice, $this->invoice_transformer);
} }
} }
return $this->decorateAdvancedFields($invoice, $entity); return $this->decorateAdvancedFields($invoice, $entity);
@ -163,7 +174,9 @@ class RecurringInvoiceExport extends BaseExport
$entity['vendor'] = $invoice->vendor ? $invoice->vendor->name : ''; $entity['vendor'] = $invoice->vendor ? $invoice->vendor->name : '';
} }
$entity['frequency'] = $invoice->frequencyForKey($invoice->frequency_id); if (in_array('recurring_invoice.frequency_id', $this->input['report_keys']) || in_array('frequency_id', $this->input['report_keys'])) {
$entity['frequency_id'] = $invoice->frequencyForKey($invoice->frequency_id);
}
return $entity; return $entity;
} }

View File

@ -24,7 +24,6 @@ use League\Csv\Writer;
class TaskExport extends BaseExport class TaskExport extends BaseExport
{ {
private Company $company;
private $entity_transformer; private $entity_transformer;
@ -47,8 +46,6 @@ class TaskExport extends BaseExport
'custom_value4' => 'custom_value4', 'custom_value4' => 'custom_value4',
'status' => 'status_id', 'status' => 'status_id',
'project' => 'project_id', 'project' => 'project_id',
'invoice' => 'invoice_id',
'client' => 'client_id',
]; ];
private array $decorate_keys = [ private array $decorate_keys = [
@ -110,14 +107,24 @@ class TaskExport extends BaseExport
$entity = []; $entity = [];
$transformed_entity = $this->entity_transformer->transform($task); $transformed_entity = $this->entity_transformer->transform($task);
if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) {
foreach (array_values($this->input['report_keys']) as $key) { foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys); $keyval = array_search($key, $this->entity_keys);
if(!$keyval) {
$keyval = array_search(str_replace("task.", "", $key), $this->entity_keys) ?? $key;
}
if(!$keyval) {
$keyval = $key;
}
if (array_key_exists($key, $transformed_entity)) { if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key]; $entity[$keyval] = $transformed_entity[$key];
} else { } elseif (array_key_exists($keyval, $transformed_entity)) {
$entity[$keyval] = ''; $entity[$keyval] = $transformed_entity[$keyval];
}
else {
$entity[$keyval] = $this->resolveKey($keyval, $task, $this->entity_transformer);
} }
} }
@ -125,23 +132,14 @@ class TaskExport extends BaseExport
$entity['end_date'] = ''; $entity['end_date'] = '';
$entity['duration'] = ''; $entity['duration'] = '';
$entity = $this->decorateAdvancedFields($task, $entity);
ksort($entity); if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) {
$this->csv->insertOne($entity); $this->csv->insertOne($entity);
} elseif (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) > 0) {
foreach (array_values($this->input['report_keys']) as $key) {
$keyval = array_search($key, $this->entity_keys);
if (array_key_exists($key, $transformed_entity)) {
$entity[$keyval] = $transformed_entity[$key];
} else { } else {
$entity[$keyval] = '';
}
}
$this->iterateLogs($task, $entity); $this->iterateLogs($task, $entity);
} }
} }
private function iterateLogs(Task $task, array $entity) private function iterateLogs(Task $task, array $entity)
@ -164,37 +162,24 @@ class TaskExport extends BaseExport
} }
foreach ($logs as $key => $item) { foreach ($logs as $key => $item) {
if (in_array('start_date', $this->input['report_keys'])) { if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) {
$entity['start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default); $entity['start_date'] = Carbon::createFromTimeStamp($item[0])->setTimezone($timezone_name)->format($date_format_default);
} }
if (in_array('end_date', $this->input['report_keys']) && $item[1] > 0) { if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] > 0) {
$entity['end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default); $entity['end_date'] = Carbon::createFromTimeStamp($item[1])->setTimezone($timezone_name)->format($date_format_default);
} }
if (in_array('end_date', $this->input['report_keys']) && $item[1] == 0) { if ((in_array('task.end_date', $this->input['report_keys']) || in_array('end_date', $this->input['report_keys'])) && $item[1] == 0) {
$entity['end_date'] = ctrans('texts.is_running'); $entity['end_date'] = ctrans('texts.is_running');
} }
if (in_array('duration', $this->input['report_keys'])) { if (in_array('task.duration', $this->input['report_keys']) || in_array('duration', $this->input['report_keys'])) {
$entity['duration'] = $task->calcDuration(); $entity['duration'] = $task->calcDuration();
} }
if (! array_key_exists('duration', $entity)) {
$entity['duration'] = '';
}
if (! array_key_exists('start_date', $entity)) {
$entity['start_date'] = '';
}
if (! array_key_exists('end_date', $entity)) {
$entity['end_date'] = '';
}
$entity = $this->decorateAdvancedFields($task, $entity); $entity = $this->decorateAdvancedFields($task, $entity);
ksort($entity);
$this->csv->insertOne($entity); $this->csv->insertOne($entity);
unset($entity['start_date']); unset($entity['start_date']);
@ -213,14 +198,6 @@ class TaskExport extends BaseExport
$entity['project'] = $task->project()->exists() ? $task->project->name : ''; $entity['project'] = $task->project()->exists() ? $task->project->name : '';
} }
if (in_array('client_id', $this->input['report_keys'])) {
$entity['client'] = $task->client ? $task->client->present()->name() : '';
}
if (in_array('invoice_id', $this->input['report_keys'])) {
$entity['invoice'] = $task->invoice ? $task->invoice->number : '';
}
return $entity; return $entity;
} }
} }

View File

@ -22,7 +22,6 @@ use League\Csv\Writer;
class VendorExport extends BaseExport class VendorExport extends BaseExport
{ {
private $company;
private $vendor_transformer; private $vendor_transformer;
@ -115,7 +114,7 @@ class VendorExport extends BaseExport
private function buildRow(Vendor $vendor) :array private function buildRow(Vendor $vendor) :array
{ {
$transformed_contact = false; $transformed_contact = [];
$transformed_vendor = $this->vendor_transformer->transform($vendor); $transformed_vendor = $this->vendor_transformer->transform($vendor);

View File

@ -49,7 +49,7 @@ class CreditFactory
$credit->user_id = $user_id; $credit->user_id = $user_id;
$credit->company_id = $company_id; $credit->company_id = $company_id;
$credit->recurring_id = null; $credit->recurring_id = null;
$credit->exchange_rate = 1;
return $credit; return $credit;
} }
} }

View File

@ -49,6 +49,7 @@ class PurchaseOrderFactory
$purchase_order->user_id = $user_id; $purchase_order->user_id = $user_id;
$purchase_order->company_id = $company_id; $purchase_order->company_id = $company_id;
$purchase_order->recurring_id = null; $purchase_order->recurring_id = null;
$purchase_order->exchange_rate = 1;
return $purchase_order; return $purchase_order;
} }

View File

@ -46,6 +46,7 @@ class QuoteFactory
$quote->user_id = $user_id; $quote->user_id = $user_id;
$quote->company_id = $company_id; $quote->company_id = $company_id;
$quote->paid_to_date = 0; $quote->paid_to_date = 0;
$quote->exchange_rate = 1;
return $quote; return $quote;
} }

View File

@ -32,7 +32,8 @@ class ExpenseFilters extends QueryFilters
} }
return $this->builder->where(function ($query) use ($filter) { return $this->builder->where(function ($query) use ($filter) {
$query->where('public_notes', 'like', '%'.$filter.'%') $query->where('number', 'like', '%'.$filter.'%')
->orWhere('public_notes', 'like', '%'.$filter.'%')
->orWhere('custom_value1', 'like', '%'.$filter.'%') ->orWhere('custom_value1', 'like', '%'.$filter.'%')
->orWhere('custom_value2', 'like', '%'.$filter.'%') ->orWhere('custom_value2', 'like', '%'.$filter.'%')
->orWhere('custom_value3', 'like', '%'.$filter.'%') ->orWhere('custom_value3', 'like', '%'.$filter.'%')
@ -164,6 +165,17 @@ class ExpenseFilters extends QueryFilters
return $this->builder; return $this->builder;
} }
if ($sort_col[0] == 'client_id') {
return $this->builder->orderBy(\App\Models\Client::select('name')
->whereColumn('clients.id', 'expenses.client_id'), $sort_col[1]);
}
if ($sort_col[0] == 'vendor_id') {
return $this->builder->orderBy(\App\Models\Vendor::select('name')
->whereColumn('vendors.id', 'expenses.vendor_id'), $sort_col[1]);
}
if (is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['public_notes', 'date', 'id_number', 'custom_value1', 'custom_value2', 'custom_value3', 'custom_value4'])) { if (is_array($sort_col) && in_array($sort_col[1], ['asc', 'desc']) && in_array($sort_col[0], ['public_notes', 'date', 'id_number', 'custom_value1', 'custom_value2', 'custom_value3', 'custom_value4'])) {
return $this->builder->orderBy($sort_col[0], $sort_col[1]); return $this->builder->orderBy($sort_col[0], $sort_col[1]);
} }

View File

@ -123,6 +123,11 @@ class PurchaseOrderFilters extends QueryFilters
return $this->builder; return $this->builder;
} }
if ($sort_col[0] == 'vendor_id') {
return $this->builder->orderBy(\App\Models\Vendor::select('name')
->whereColumn('vendors.id', 'purchase_orders.vendor_id'), $sort_col[1]);
}
return $this->builder->orderBy($sort_col[0], $sort_col[1]); return $this->builder->orderBy($sort_col[0], $sort_col[1]);
} }

View File

@ -81,6 +81,19 @@ class AccountTransformer implements AccountTransformerInterface
public function transformAccount($account) public function transformAccount($account)
{ {
$current_balance = 0;
$account_currency = '';
if(property_exists($account, 'currentBalance')) {
$current_balance = $account->currentBalance->amount ?? 0;
$account_currency = $account->currentBalance->currency ?? '';
}
elseif(property_exists($account, 'balance')){
$current_balance = $account->balance->amount ?? 0;
$account_currency = $account->balance->currency ?? '';
}
return [ return [
'id' => $account->id, 'id' => $account->id,
'account_type' => $account->CONTAINER, 'account_type' => $account->CONTAINER,
@ -92,8 +105,8 @@ class AccountTransformer implements AccountTransformerInterface
'provider_id' => $account->providerId, 'provider_id' => $account->providerId,
'provider_name' => $account->providerName, 'provider_name' => $account->providerName,
'nickname' => property_exists($account, 'nickname') ? $account->nickname : '', 'nickname' => property_exists($account, 'nickname') ? $account->nickname : '',
'current_balance' => property_exists($account, 'currentBalance') ? $account->currentBalance->amount : 0, 'current_balance' => $current_balance,
'account_currency' => property_exists($account, 'currency') ? $account->currentBalance->currency : '', 'account_currency' => $account_currency,
]; ];
} }
} }

View File

@ -185,6 +185,21 @@ class Yodlee
} }
} }
public function getAccountSummary($account_id)
{
$token = $this->getAccessToken();
$response = Http::withHeaders($this->getHeaders(["Authorization" => "Bearer {$token}"]))->get($this->getEndpoint(). "/accounts/{$account_id}", []);
if ($response->successful()) {
return $response->object();
}
if ($response->failed()) {
return false;
}
}
public function deleteAccount($account_id) public function deleteAccount($account_id)
{ {
$token = $this->getAccessToken(); $token = $this->getAccessToken();

View File

@ -238,14 +238,20 @@ class InvoiceItemSum
{ {
$this->rule->tax($this->item); $this->rule->tax($this->item);
$precision = strlen(substr(strrchr($this->rule->tax_rate1, "."), 1));
$this->item->tax_name1 = $this->rule->tax_name1; $this->item->tax_name1 = $this->rule->tax_name1;
$this->item->tax_rate1 = $this->rule->tax_rate1; $this->item->tax_rate1 = round($this->rule->tax_rate1, $precision);
$precision = strlen(substr(strrchr($this->rule->tax_rate2, "."), 1));
$this->item->tax_name2 = $this->rule->tax_name2; $this->item->tax_name2 = $this->rule->tax_name2;
$this->item->tax_rate2 = $this->rule->tax_rate2; $this->item->tax_rate2 = round($this->rule->tax_rate2, $precision);
$precision = strlen(substr(strrchr($this->rule->tax_rate3, "."), 1));
$this->item->tax_name3 = $this->rule->tax_name3; $this->item->tax_name3 = $this->rule->tax_name3;
$this->item->tax_rate3 = $this->rule->tax_rate3; $this->item->tax_rate3 = round($this->rule->tax_rate3, $precision);
return $this; return $this;
} }

View File

@ -11,24 +11,23 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
use App\Models\Activity;
use App\Transformers\ActivityTransformer;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\Ninja;
use App\Utils\PhantomJS\Phantom;
use App\Utils\Traits\Pdf\PageNumbering;
use App\Utils\Traits\Pdf\PdfMaker;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use stdClass; use stdClass;
use Symfony\Component\HttpFoundation\StreamedResponse; use App\Utils\Ninja;
use App\Models\Activity;
use Illuminate\Http\Request;
use App\Utils\Traits\MakesHash;
use App\Utils\PhantomJS\Phantom;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\Traits\Pdf\PdfMaker;
use App\Utils\Traits\Pdf\PageNumbering;
use Illuminate\Support\Facades\Storage;
use App\Transformers\ActivityTransformer;
use App\Http\Requests\Activity\ShowActivityRequest;
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
class ActivityController extends BaseController class ActivityController extends BaseController
{ {
use PdfMaker, PageNumbering; use PdfMaker, PageNumbering, MakesHash;
protected $entity_type = Activity::class; protected $entity_type = Activity::class;
@ -39,50 +38,6 @@ class ActivityController extends BaseController
parent::__construct(); parent::__construct();
} }
/**
* @OA\Get(
* path="/api/v1/activities",
* operationId="getActivities",
* tags={"actvities"},
* summary="Gets a list of actvities",
* description="Lists all activities",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(ref="#/components/parameters/index"),
* @OA\Parameter(
* name="rows",
* in="query",
* description="The number of activities to return",
* example="50",
* required=false,
* @OA\Schema(
* type="number",
* format="integer",
* ),
* ),
* @OA\Response(
* response=200,
* description="A list of actvities",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* @OA\JsonContent(ref="#/components/schemas/Activity"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param Request $request
* @return Response|mixed
*/
public function index(Request $request) public function index(Request $request)
{ {
$default_activities = $request->has('rows') ? $request->input('rows') : 75; $default_activities = $request->has('rows') ? $request->input('rows') : 75;
@ -115,47 +70,36 @@ class ActivityController extends BaseController
return $this->listResponse($activities); return $this->listResponse($activities);
} }
/** public function entityActivity(ShowActivityRequest $request)
* @OA\Get( {
* path="/api/v1/actvities/download_entity/{activity_id}",
* operationId="getActivityHistoricalEntityPdf", $default_activities = request()->has('rows') ? request()->input('rows') : 75;
* tags={"actvities"},
* summary="Gets a PDF for the given activity", $activities = Activity::with('user')
* description="Gets a PDF for the given activity", ->orderBy('created_at', 'DESC')
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), ->company()
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"), ->where("{$request->entity}_id", $request->entity_id)
* @OA\Parameter( ->take($default_activities);
* name="activity_id",
* in="path", /** @var \App\Models\User auth()->user() */
* description="The Activity Hashed ID", $user = auth()->user();
* example="D2J234DFA",
* required=true, if (!$user->isAdmin()) {
* @OA\Schema( $activities->where('user_id', auth()->user()->id);
* type="string", }
* format="string",
* ), $system = ctrans('texts.system');
* ),
* @OA\Response( $data = $activities->cursor()->map(function ($activity) use ($system) {
* response=200,
* description="PDF File", return $activity->activity_string();
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), });
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* ), return response()->json(['data' => $data->toArray()], 200);
* @OA\Response(
* response=404, }
* description="No file exists for the given record",
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
* @param DownloadHistoricalEntityRequest $request
* @param Activity $activity
* @return JsonResponse|StreamedResponse
*/
public function downloadHistoricalEntity(DownloadHistoricalEntityRequest $request, Activity $activity) public function downloadHistoricalEntity(DownloadHistoricalEntityRequest $request, Activity $activity)
{ {
$backup = $activity->backup; $backup = $activity->backup;
@ -204,6 +148,8 @@ class ActivityController extends BaseController
} }
} }
$activity->company->setLocale();
if (isset($activity->invoice_id)) { if (isset($activity->invoice_id)) {
$filename = $activity->invoice->numberFormatter().'.pdf'; $filename = $activity->invoice->numberFormatter().'.pdf';
} elseif (isset($activity->quote_id)) { } elseif (isset($activity->quote_id)) {

View File

@ -209,7 +209,12 @@ class BankIntegrationController extends BaseController
$accounts = $yodlee->getAccounts(); $accounts = $yodlee->getAccounts();
foreach ($accounts as $account) { foreach ($accounts as $account) {
if (!BankIntegration::withTrashed()->where('bank_account_id', $account['id'])->where('company_id', $user->company()->id)->exists()) { if ($bi = BankIntegration::withTrashed()->where('bank_account_id', $account['id'])->where('company_id', $user->company()->id)->first()){
$bi->balance = $account['current_balance'];
$bi->currency = $account['account_currency'];
$bi->save();
}
else {
$bank_integration = new BankIntegration(); $bank_integration = new BankIntegration();
$bank_integration->company_id = $user->company()->id; $bank_integration->company_id = $user->company()->id;
$bank_integration->account_id = $user->account_id; $bank_integration->account_id = $user->account_id;

View File

@ -85,22 +85,20 @@ class InvitationController extends Controller
->with('contact.client') ->with('contact.client')
->firstOrFail(); ->firstOrFail();
//09-03-2023 do not show entity if the invitation has been trashed.
if ($invitation->trashed() || $invitation->{$entity}->is_deleted) { if ($invitation->trashed() || $invitation->{$entity}->is_deleted) {
return $this->render('generic.not_available', ['account' => $invitation->company->account, 'company' => $invitation->company]); return $this->render('generic.not_available', ['account' => $invitation->company->account, 'company' => $invitation->company]);
} }
/* 12/01/2022 Clean up an edge case where if the contact is trashed, restore if a invitation comes back. */
if ($invitation->contact->trashed()) { if ($invitation->contact->trashed()) {
$invitation->contact->restore(); $invitation->contact->restore();
} }
/* Return early if we have the correct client_hash embedded */
$client_contact = $invitation->contact; $client_contact = $invitation->contact;
if (empty($client_contact->email)) { if (empty($client_contact->email)) {
$client_contact->email = Str::random(15) . "@example.com"; $client_contact->email = Str::random(15) . "@example.com";
} $client_contact->save(); $client_contact->save();
}
if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) { if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) {
request()->session()->invalidate(); request()->session()->invalidate();

View File

@ -86,7 +86,7 @@ class InvoiceController extends Controller
public function showBlob($hash) public function showBlob($hash)
{ {
$data = Cache::pull($hash); $data = Cache::get($hash);
match($data['entity_type']){ match($data['entity_type']){
'invoice' => $invitation = InvoiceInvitation::withTrashed()->find($data['invitation_id']), 'invoice' => $invitation = InvoiceInvitation::withTrashed()->find($data['invitation_id']),

View File

@ -24,6 +24,7 @@ use App\Http\Requests\CompanyGateway\UpdateCompanyGatewayRequest;
use App\Jobs\Util\ApplePayDomain; use App\Jobs\Util\ApplePayDomain;
use App\Models\Client; use App\Models\Client;
use App\Models\CompanyGateway; use App\Models\CompanyGateway;
use App\PaymentDrivers\CheckoutCom\CheckoutSetupWebhook;
use App\PaymentDrivers\Stripe\Jobs\StripeWebhook; use App\PaymentDrivers\Stripe\Jobs\StripeWebhook;
use App\Repositories\CompanyRepository; use App\Repositories\CompanyRepository;
use App\Transformers\CompanyGatewayTransformer; use App\Transformers\CompanyGatewayTransformer;
@ -49,6 +50,8 @@ class CompanyGatewayController extends BaseController
private array $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23']; private array $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23'];
private string $checkout_key = '3758e7f7c6f4cecf0f4f348b9a00f456';
/** /**
* CompanyGatewayController constructor. * CompanyGatewayController constructor.
* @param CompanyRepository $company_repo * @param CompanyRepository $company_repo
@ -211,6 +214,9 @@ class CompanyGatewayController extends BaseController
if (in_array($company_gateway->gateway_key, $this->stripe_keys)) { if (in_array($company_gateway->gateway_key, $this->stripe_keys)) {
StripeWebhook::dispatch($company_gateway->company->company_key, $company_gateway->id); StripeWebhook::dispatch($company_gateway->company->company_key, $company_gateway->id);
} }
elseif($company_gateway->gateway_key == $this->checkout_key) {
CheckoutSetupWebhook::dispatch($company_gateway->company->company_key, $company_gateway->id);
}
return $this->itemResponse($company_gateway); return $this->itemResponse($company_gateway);
} }
@ -382,7 +388,9 @@ class CompanyGatewayController extends BaseController
$company_gateway->save(); $company_gateway->save();
// ApplePayDomain::dispatch($company_gateway, $company_gateway->company->db); if($company_gateway->gateway_key == $this->checkout_key) {
CheckoutSetupWebhook::dispatch($company_gateway->company->company_key, $company_gateway->fresh()->id);
}
return $this->itemResponse($company_gateway); return $this->itemResponse($company_gateway);
} }

View File

@ -11,34 +11,35 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Events\Credit\CreditWasCreated; use App\Utils\Ninja;
use App\Events\Credit\CreditWasUpdated; use App\Models\Client;
use App\Factory\CloneCreditFactory; use App\Models\Credit;
use App\Models\Account;
use App\Models\Invoice;
use Illuminate\Http\Response;
use App\Factory\CreditFactory; use App\Factory\CreditFactory;
use App\Filters\CreditFilters; use App\Filters\CreditFilters;
use App\Http\Requests\Credit\ActionCreditRequest; use App\Jobs\Credit\ZipCredits;
use App\Utils\Traits\MakesHash;
use App\Jobs\Entity\EmailEntity;
use App\Factory\CloneCreditFactory;
use App\Services\PdfMaker\PdfMerge;
use Illuminate\Support\Facades\App;
use App\Utils\Traits\SavesDocuments;
use App\Repositories\CreditRepository;
use App\Events\Credit\CreditWasCreated;
use App\Events\Credit\CreditWasUpdated;
use App\Transformers\CreditTransformer;
use Illuminate\Support\Facades\Storage;
use App\Http\Requests\Credit\BulkCreditRequest; use App\Http\Requests\Credit\BulkCreditRequest;
use App\Http\Requests\Credit\CreateCreditRequest;
use App\Http\Requests\Credit\DestroyCreditRequest;
use App\Http\Requests\Credit\EditCreditRequest; use App\Http\Requests\Credit\EditCreditRequest;
use App\Http\Requests\Credit\ShowCreditRequest; use App\Http\Requests\Credit\ShowCreditRequest;
use App\Http\Requests\Credit\StoreCreditRequest; use App\Http\Requests\Credit\StoreCreditRequest;
use App\Http\Requests\Credit\ActionCreditRequest;
use App\Http\Requests\Credit\CreateCreditRequest;
use App\Http\Requests\Credit\UpdateCreditRequest; use App\Http\Requests\Credit\UpdateCreditRequest;
use App\Http\Requests\Credit\UploadCreditRequest; use App\Http\Requests\Credit\UploadCreditRequest;
use App\Jobs\Credit\ZipCredits; use App\Http\Requests\Credit\DestroyCreditRequest;
use App\Jobs\Entity\EmailEntity;
use App\Models\Account;
use App\Models\Client;
use App\Models\Credit;
use App\Models\Invoice;
use App\Repositories\CreditRepository;
use App\Services\PdfMaker\PdfMerge;
use App\Transformers\CreditTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
/** /**
* Class CreditController. * Class CreditController.
@ -691,6 +692,8 @@ class CreditController extends BaseController
$credit = $invitation->credit; $credit = $invitation->credit;
App::setLocale($invitation->contact->preferredLocale());
$file = $credit->service()->getCreditPdf($invitation); $file = $credit->service()->getCreditPdf($invitation);
$headers = ['Content-Type' => 'application/pdf']; $headers = ['Content-Type' => 'application/pdf'];

View File

@ -81,7 +81,8 @@ class ImportController extends Controller
/** @var UploadedFile $file */ /** @var UploadedFile $file */
foreach ($request->files->get('files') as $entityType => $file) { foreach ($request->files->get('files') as $entityType => $file) {
$contents = file_get_contents($file->getPathname()); $contents = file_get_contents($file->getPathname());
// $contents = mb_convert_encoding($contents, 'UTF-16LE', 'UTF-8');
$contents = $this->convertEncoding($contents);
// Store the csv in cache with an expiry of 10 minutes // Store the csv in cache with an expiry of 10 minutes
Cache::put($hash.'-'.$entityType, base64_encode($contents), 600); Cache::put($hash.'-'.$entityType, base64_encode($contents), 600);
@ -100,6 +101,18 @@ class ImportController extends Controller
return response()->json($data); return response()->json($data);
} }
private function convertEncoding($data)
{
$enc = mb_detect_encoding($data, mb_list_encodings(), true);
if($enc !== false) {
$data = mb_convert_encoding($data, "UTF-8", $enc);
}
return $data;
}
public function import(ImportRequest $request) public function import(ImportRequest $request)
{ {
$data = $request->all(); $data = $request->all();

View File

@ -12,38 +12,39 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Events\Invoice\InvoiceWasCreated; use App\Utils\Ninja;
use App\Events\Invoice\InvoiceWasUpdated; use App\Models\Quote;
use App\Factory\CloneInvoiceFactory; use App\Models\Account;
use App\Factory\CloneInvoiceToQuoteFactory; use App\Models\Invoice;
use App\Jobs\Cron\AutoBill;
use Illuminate\Http\Response;
use App\Factory\InvoiceFactory; use App\Factory\InvoiceFactory;
use App\Filters\InvoiceFilters; use App\Filters\InvoiceFilters;
use App\Http\Requests\Invoice\ActionInvoiceRequest; use App\Utils\Traits\MakesHash;
use App\Jobs\Invoice\ZipInvoices;
use App\Services\PdfMaker\PdfMerge;
use Illuminate\Support\Facades\App;
use App\Factory\CloneInvoiceFactory;
use App\Jobs\Invoice\BulkInvoiceJob;
use App\Utils\Traits\SavesDocuments;
use App\Jobs\Invoice\UpdateReminders;
use App\Transformers\QuoteTransformer;
use App\Repositories\InvoiceRepository;
use Illuminate\Support\Facades\Storage;
use App\Transformers\InvoiceTransformer;
use App\Events\Invoice\InvoiceWasCreated;
use App\Events\Invoice\InvoiceWasUpdated;
use App\Factory\CloneInvoiceToQuoteFactory;
use App\Http\Requests\Invoice\BulkInvoiceRequest; use App\Http\Requests\Invoice\BulkInvoiceRequest;
use App\Http\Requests\Invoice\CreateInvoiceRequest;
use App\Http\Requests\Invoice\DestroyInvoiceRequest;
use App\Http\Requests\Invoice\EditInvoiceRequest; use App\Http\Requests\Invoice\EditInvoiceRequest;
use App\Http\Requests\Invoice\ShowInvoiceRequest; use App\Http\Requests\Invoice\ShowInvoiceRequest;
use App\Http\Requests\Invoice\StoreInvoiceRequest; use App\Http\Requests\Invoice\StoreInvoiceRequest;
use App\Http\Requests\Invoice\ActionInvoiceRequest;
use App\Http\Requests\Invoice\CreateInvoiceRequest;
use App\Http\Requests\Invoice\UpdateInvoiceRequest; use App\Http\Requests\Invoice\UpdateInvoiceRequest;
use App\Http\Requests\Invoice\UpdateReminderRequest;
use App\Http\Requests\Invoice\UploadInvoiceRequest; use App\Http\Requests\Invoice\UploadInvoiceRequest;
use App\Jobs\Cron\AutoBill; use App\Http\Requests\Invoice\DestroyInvoiceRequest;
use App\Jobs\Invoice\BulkInvoiceJob; use App\Http\Requests\Invoice\UpdateReminderRequest;
use App\Jobs\Invoice\UpdateReminders;
use App\Jobs\Invoice\ZipInvoices;
use App\Models\Account;
use App\Models\Invoice;
use App\Models\Quote;
use App\Repositories\InvoiceRepository;
use App\Services\PdfMaker\PdfMerge;
use App\Transformers\InvoiceTransformer;
use App\Transformers\QuoteTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
/** /**
* Class InvoiceController. * Class InvoiceController.
@ -821,6 +822,8 @@ class InvoiceController extends BaseController
$invoice = $invitation->invoice; $invoice = $invitation->invoice;
App::setLocale($invitation->contact->preferredLocale());
$file_name = $invoice->numberFormatter().'.pdf'; $file_name = $invoice->numberFormatter().'.pdf';
$file = (new \App\Jobs\Entity\CreateRawPdf($invitation, $invitation->company->db))->handle(); $file = (new \App\Jobs\Entity\CreateRawPdf($invitation, $invitation->company->db))->handle();

View File

@ -285,7 +285,7 @@ class PreviewController extends BaseController
return $maker->getCompiledHTML(); return $maker->getCompiledHTML();
} }
} catch(\Exception $e) { } catch(\Exception $e) {
nlog($e->getMessage()); // nlog($e->getMessage());
DB::connection(config('database.default'))->rollBack(); DB::connection(config('database.default'))->rollBack();
return; return;

View File

@ -11,6 +11,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Utils\Ninja;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Jobs\Util\UnlinkFile; use App\Jobs\Util\UnlinkFile;
use App\Exceptions\SystemError; use App\Exceptions\SystemError;
@ -30,7 +31,9 @@ class ProtectedDownloadController extends BaseController
abort(404, 'File no longer available'); abort(404, 'File no longer available');
} }
return response()->download($hashed_path, basename($hashed_path), [])->deleteFileAfterSend(true); return response()->streamDownload(function () use ($hashed_path) {
echo Storage::get($hashed_path);
}, basename($hashed_path), []);
} }

View File

@ -11,32 +11,33 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Events\PurchaseOrder\PurchaseOrderWasCreated; use App\Utils\Ninja;
use App\Events\PurchaseOrder\PurchaseOrderWasUpdated; use App\Models\Client;
use App\Models\Account;
use App\Models\PurchaseOrder;
use Illuminate\Http\Response;
use App\Utils\Traits\MakesHash;
use App\Services\PdfMaker\PdfMerge;
use Illuminate\Support\Facades\App;
use App\Utils\Traits\SavesDocuments;
use App\Factory\PurchaseOrderFactory; use App\Factory\PurchaseOrderFactory;
use App\Filters\PurchaseOrderFilters; use App\Filters\PurchaseOrderFilters;
use App\Http\Requests\PurchaseOrder\ActionPurchaseOrderRequest; use Illuminate\Support\Facades\Storage;
use App\Jobs\PurchaseOrder\ZipPurchaseOrders;
use App\Repositories\PurchaseOrderRepository;
use App\Jobs\PurchaseOrder\PurchaseOrderEmail;
use App\Transformers\PurchaseOrderTransformer;
use App\Events\PurchaseOrder\PurchaseOrderWasCreated;
use App\Events\PurchaseOrder\PurchaseOrderWasUpdated;
use App\Http\Requests\PurchaseOrder\BulkPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\BulkPurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\CreatePurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\DestroyPurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\EditPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\EditPurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\ShowPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\ShowPurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\StorePurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\StorePurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\ActionPurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\CreatePurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\UpdatePurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\UpdatePurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\UploadPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\UploadPurchaseOrderRequest;
use App\Jobs\PurchaseOrder\PurchaseOrderEmail; use App\Http\Requests\PurchaseOrder\DestroyPurchaseOrderRequest;
use App\Jobs\PurchaseOrder\ZipPurchaseOrders;
use App\Models\Account;
use App\Models\Client;
use App\Models\PurchaseOrder;
use App\Repositories\PurchaseOrderRepository;
use App\Services\PdfMaker\PdfMerge;
use App\Transformers\PurchaseOrderTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
class PurchaseOrderController extends BaseController class PurchaseOrderController extends BaseController
{ {

View File

@ -11,38 +11,39 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Events\Quote\QuoteWasCreated; use App\Utils\Ninja;
use App\Events\Quote\QuoteWasUpdated; use App\Models\Quote;
use App\Factory\CloneQuoteFactory; use App\Models\Client;
use App\Factory\CloneQuoteToInvoiceFactory; use App\Models\Account;
use App\Factory\CloneQuoteToProjectFactory; use App\Models\Invoice;
use Illuminate\Http\Request;
use App\Factory\QuoteFactory; use App\Factory\QuoteFactory;
use App\Filters\QuoteFilters; use App\Filters\QuoteFilters;
use App\Http\Requests\Quote\ActionQuoteRequest; use App\Jobs\Quote\ZipQuotes;
use App\Http\Requests\Quote\BulkActionQuoteRequest; use Illuminate\Http\Response;
use App\Http\Requests\Quote\CreateQuoteRequest; use App\Utils\Traits\MakesHash;
use App\Http\Requests\Quote\DestroyQuoteRequest; use App\Factory\CloneQuoteFactory;
use App\Services\PdfMaker\PdfMerge;
use Illuminate\Support\Facades\App;
use App\Utils\Traits\SavesDocuments;
use App\Events\Quote\QuoteWasCreated;
use App\Events\Quote\QuoteWasUpdated;
use App\Repositories\QuoteRepository;
use App\Transformers\QuoteTransformer;
use App\Utils\Traits\GeneratesCounter;
use Illuminate\Support\Facades\Storage;
use App\Transformers\InvoiceTransformer;
use App\Factory\CloneQuoteToInvoiceFactory;
use App\Factory\CloneQuoteToProjectFactory;
use App\Http\Requests\Quote\EditQuoteRequest; use App\Http\Requests\Quote\EditQuoteRequest;
use App\Http\Requests\Quote\ShowQuoteRequest; use App\Http\Requests\Quote\ShowQuoteRequest;
use App\Http\Requests\Quote\StoreQuoteRequest; use App\Http\Requests\Quote\StoreQuoteRequest;
use App\Http\Requests\Quote\ActionQuoteRequest;
use App\Http\Requests\Quote\CreateQuoteRequest;
use App\Http\Requests\Quote\UpdateQuoteRequest; use App\Http\Requests\Quote\UpdateQuoteRequest;
use App\Http\Requests\Quote\UploadQuoteRequest; use App\Http\Requests\Quote\UploadQuoteRequest;
use App\Jobs\Quote\ZipQuotes; use App\Http\Requests\Quote\DestroyQuoteRequest;
use App\Models\Account; use App\Http\Requests\Quote\BulkActionQuoteRequest;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\Quote;
use App\Repositories\QuoteRepository;
use App\Services\PdfMaker\PdfMerge;
use App\Transformers\InvoiceTransformer;
use App\Transformers\QuoteTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
/** /**
* Class QuoteController. * Class QuoteController.
@ -825,6 +826,8 @@ class QuoteController extends BaseController
$contact = $invitation->contact; $contact = $invitation->contact;
$quote = $invitation->quote; $quote = $invitation->quote;
App::setLocale($invitation->contact->preferredLocale());
$file = $quote->service()->getQuotePdf($contact); $file = $quote->service()->getQuotePdf($contact);
$headers = ['Content-Type' => 'application/pdf']; $headers = ['Content-Type' => 'application/pdf'];

View File

@ -11,29 +11,28 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Events\RecurringInvoice\RecurringInvoiceWasCreated; use App\Utils\Ninja;
use App\Events\RecurringInvoice\RecurringInvoiceWasUpdated; use App\Models\Account;
use Illuminate\Http\Response;
use App\Utils\Traits\MakesHash;
use App\Models\RecurringInvoice;
use App\Utils\Traits\SavesDocuments;
use App\Factory\RecurringInvoiceFactory; use App\Factory\RecurringInvoiceFactory;
use App\Filters\RecurringInvoiceFilters; use App\Filters\RecurringInvoiceFilters;
use App\Http\Requests\RecurringInvoice\ActionRecurringInvoiceRequest; use App\Jobs\RecurringInvoice\UpdateRecurring;
use App\Repositories\RecurringInvoiceRepository;
use App\Transformers\RecurringInvoiceTransformer;
use App\Events\RecurringInvoice\RecurringInvoiceWasCreated;
use App\Events\RecurringInvoice\RecurringInvoiceWasUpdated;
use App\Http\Requests\RecurringInvoice\BulkRecurringInvoiceRequest; use App\Http\Requests\RecurringInvoice\BulkRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\CreateRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\DestroyRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\EditRecurringInvoiceRequest; use App\Http\Requests\RecurringInvoice\EditRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\ShowRecurringInvoiceRequest; use App\Http\Requests\RecurringInvoice\ShowRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest; use App\Http\Requests\RecurringInvoice\StoreRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\ActionRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\CreateRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\UpdateRecurringInvoiceRequest; use App\Http\Requests\RecurringInvoice\UpdateRecurringInvoiceRequest;
use App\Http\Requests\RecurringInvoice\UploadRecurringInvoiceRequest; use App\Http\Requests\RecurringInvoice\UploadRecurringInvoiceRequest;
use App\Jobs\RecurringInvoice\UpdateRecurring; use App\Http\Requests\RecurringInvoice\DestroyRecurringInvoiceRequest;
use App\Models\Account;
use App\Models\RecurringInvoice;
use App\Repositories\RecurringInvoiceRepository;
use App\Transformers\RecurringInvoiceTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
/** /**
* Class RecurringInvoiceController. * Class RecurringInvoiceController.
@ -567,6 +566,8 @@ class RecurringInvoiceController extends BaseController
$invoice = $invitation->recurring_invoice; $invoice = $invitation->recurring_invoice;
\Illuminate\Support\Facades\App::setLocale($invitation->contact->preferredLocale());
$file_name = $invoice->numberFormatter().'.pdf'; $file_name = $invoice->numberFormatter().'.pdf';
$file = (new \App\Jobs\Entity\CreateRawPdf($invitation, $invitation->company->db))->handle(); $file = (new \App\Jobs\Entity\CreateRawPdf($invitation, $invitation->company->db))->handle();

View File

@ -53,7 +53,7 @@ class SelfUpdateController extends BaseController
nlog('Test filesystem is writable'); nlog('Test filesystem is writable');
$this->testWritable(); // $this->testWritable();
nlog('Clear cache directory'); nlog('Clear cache directory');

View File

@ -11,16 +11,17 @@
namespace App\Http\Controllers\VendorPortal; namespace App\Http\Controllers\VendorPortal;
use App\Events\Misc\InvitationWasViewed;
use App\Events\PurchaseOrder\PurchaseOrderWasViewed;
use App\Http\Controllers\Controller;
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
use App\Models\PurchaseOrderInvitation;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesHash;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\MakesDates;
use Illuminate\Support\Facades\App;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\Models\PurchaseOrderInvitation;
use App\Events\Misc\InvitationWasViewed;
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
use App\Events\PurchaseOrder\PurchaseOrderWasViewed;
/** /**
* Class InvitationController. * Class InvitationController.
@ -89,6 +90,8 @@ class InvitationController extends Controller
return response()->json(["message" => "no record found"], 400); return response()->json(["message" => "no record found"], 400);
} }
App::setLocale($invitation->contact->preferredLocale());
$file_name = $invitation->purchase_order->numberFormatter().'.pdf'; $file_name = $invitation->purchase_order->numberFormatter().'.pdf';
$file = (new CreatePurchaseOrderPdf($invitation))->rawPdf(); $file = (new CreatePurchaseOrderPdf($invitation))->rawPdf();

View File

@ -20,15 +20,12 @@ use Illuminate\Support\Str;
use App\Models\QuoteInvitation; use App\Models\QuoteInvitation;
use App\Utils\VendorHtmlEngine; use App\Utils\VendorHtmlEngine;
use App\Models\CreditInvitation; use App\Models\CreditInvitation;
use App\Services\Pdf\PdfBuilder;
use App\Services\Pdf\PdfService;
use App\Models\InvoiceInvitation; use App\Models\InvoiceInvitation;
use App\Services\Pdf\PdfDesigner;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use App\Services\Pdf\PdfConfiguration;
use App\Models\PurchaseOrderInvitation; use App\Models\PurchaseOrderInvitation;
use App\Models\RecurringInvoiceInvitation; use App\Models\RecurringInvoiceInvitation;
use App\Jobs\Vendor\CreatePurchaseOrderPdf; use App\Jobs\Vendor\CreatePurchaseOrderPdf;
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
class PdfSlot extends Component class PdfSlot extends Component
{ {
@ -48,12 +45,12 @@ class PdfSlot extends Component
private $entity_type; private $entity_type;
protected $listeners = ['viewportChanged' => 'getPdf'];
public $show_cost = true; public $show_cost = true;
public $show_quantity = true; public $show_quantity = true;
public $show_line_total = true;
public $route_entity = 'client'; public $route_entity = 'client';
public function mount() public function mount()
@ -106,11 +103,12 @@ class PdfSlot extends Component
$this->settings = $this->entity->client ? $this->entity->client->getMergedSettings() : $this->entity->company->settings; $this->settings = $this->entity->client ? $this->entity->client->getMergedSettings() : $this->entity->company->settings;
$this->show_cost = in_array('$product.unit_cost', $this->settings->pdf_variables->product_columns); $this->show_cost = in_array('$product.unit_cost', $this->settings->pdf_variables->product_columns);
$this->show_quantity = in_array('$product.quantity', $this->settings->pdf_variables->product_columns); $this->show_line_total = in_array('$product.line_total', $this->settings->pdf_variables->product_columns);
if($this->entity_type == 'quote' && !$this->settings->sync_invoice_quote_columns ){ if($this->entity_type == 'quote' && !$this->settings->sync_invoice_quote_columns ){
$this->show_cost = in_array('$product.unit_cost', $this->settings->pdf_variables->product_quote_columns); $this->show_cost = in_array('$product.unit_cost', $this->settings->pdf_variables->product_quote_columns);
$this->show_quantity = in_array('$product.quantity', $this->settings->pdf_variables->product_quote_columns); $this->show_quantity = in_array('$product.quantity', $this->settings->pdf_variables->product_quote_columns);
$this->show_line_total = in_array('$product.line_total', $this->settings->pdf_variables->product_quote_columns);
} }
$this->html_variables = $this->entity->client ? $this->html_variables = $this->entity->client ?
@ -175,20 +173,20 @@ class PdfSlot extends Component
if($this->entity_type == 'invoice' || $this->entity_type == 'recurring_invoice') { if($this->entity_type == 'invoice' || $this->entity_type == 'recurring_invoice') {
foreach($this->settings->pdf_variables->invoice_details as $variable) foreach($this->settings->pdf_variables->invoice_details as $variable)
$entity_details .= "<div class='flex px-3 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-1 w-36 block entity-field'>{$variable}</p></div>"; $entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-5 w-36 block entity-field'>{$variable}</p></div>";
} }
elseif($this->entity_type == 'quote'){ elseif($this->entity_type == 'quote'){
foreach($this->settings->pdf_variables->quote_details as $variable) foreach($this->settings->pdf_variables->quote_details as $variable)
$entity_details .= "<div class='flex px-3 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-1 w-36 block entity-field'>{$variable}</p></div>"; $entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-5 w-36 block entity-field'>{$variable}</p></div>";
} }
elseif($this->entity_type == 'credit') { elseif($this->entity_type == 'credit') {
foreach($this->settings->pdf_variables->credit_details as $variable) foreach($this->settings->pdf_variables->credit_details as $variable)
$entity_details .= "<div class='flex px-3 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-1 w-36 block entity-field'>{$variable}</p></div>"; $entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-5 w-36 block entity-field'>{$variable}</p></div>";
} }
elseif($this->entity_type == 'purchase_order'){ elseif($this->entity_type == 'purchase_order'){
foreach($this->settings->pdf_variables->purchase_order_details as $variable) foreach($this->settings->pdf_variables->purchase_order_details as $variable)
$entity_details .= "<div class='flex px-3 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-1 w-36 block entity-field'>{$variable}</p></div>"; $entity_details .= "<div class='flex px-5 block'><p class= w-36 block'>{$variable}_label</p><p class='pl-5 w-36 block entity-field'>{$variable}</p></div>";
} }
return $this->convertVariables($entity_details); return $this->convertVariables($entity_details);
@ -231,13 +229,16 @@ class PdfSlot extends Component
private function getProducts() private function getProducts()
{ {
$product_items = collect($this->entity->line_items)->filter(function ($item) { $product_items = collect($this->entity->line_items)->filter(function ($item) {
return $item->type_id == 1 || $item->type_id == 6 || $item->type_id == 5; return $item->type_id == 1 || $item->type_id == 6 || $item->type_id == 5;
})->map(function ($item){ })->map(function ($item){
return [ return [
'quantity' => $item->quantity, 'quantity' => $item->quantity,
'cost' => Number::formatMoney($item->cost, $this->entity->client ?: $this->entity->vendor), 'cost' => Number::formatMoney($item->cost, $this->entity->client ?: $this->entity->vendor),
'notes' => $item->notes, 'notes' => $this->invitation->company->markdown_enabled ? DesignHelpers::parseMarkdownToHtml($item->notes) : $item->notes,
'line_total' => Number::formatMoney($item->line_total, $this->entity->client ?: $this->entity->vendor), 'line_total' => Number::formatMoney($item->line_total, $this->entity->client ?: $this->entity->vendor),
]; ];
}); });
@ -253,7 +254,7 @@ class PdfSlot extends Component
return [ return [
'quantity' => $item->quantity, 'quantity' => $item->quantity,
'cost' => Number::formatMoney($item->cost, $this->entity->client ?: $this->entity->vendor), 'cost' => Number::formatMoney($item->cost, $this->entity->client ?: $this->entity->vendor),
'notes' => $item->notes, 'notes' => $this->invitation->company->markdown_enabled ? DesignHelpers::parseMarkdownToHtml($item->notes) : $item->notes,
'line_total' => Number::formatMoney($item->line_total, $this->entity->client ?: $this->entity->vendor), 'line_total' => Number::formatMoney($item->line_total, $this->entity->client ?: $this->entity->vendor),
]; ];
}); });

View File

@ -53,7 +53,6 @@ class SetInviteDb
/* Try and determine the DB from the invitation key STRING*/ /* Try and determine the DB from the invitation key STRING*/
if (config('ninja.db.multi_db_enabled')) { if (config('ninja.db.multi_db_enabled')) {
// nlog("/ Try and determine the DB from the invitation key /");
$hashids = new Hashids(config('ninja.hash_salt'), 10); $hashids = new Hashids(config('ninja.hash_salt'), 10);
$segments = explode('-', $request->route('invitation_key')); $segments = explode('-', $request->route('invitation_key'));

View File

@ -12,10 +12,12 @@
namespace App\Http\Requests\Activity; namespace App\Http\Requests\Activity;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\Models\Activity; use App\Utils\Traits\MakesHash;
class ShowActivityRequest extends Request class ShowActivityRequest extends Request
{ {
use MakesHash;
/** /**
* Determine if the user is authorized to make this request. * Determine if the user is authorized to make this request.
* *
@ -23,7 +25,25 @@ class ShowActivityRequest extends Request
*/ */
public function authorize() : bool public function authorize() : bool
{ {
// return auth()->user()->isAdmin(); return true;
return auth()->user()->can('view', Activity::class); }
public function rules()
{
return [
'entity' => 'bail|required|in:invoice,quote,credit,purchase_order,payment,client,vendor,expense,task,project,subscription,recurring_invoice,',
'entity_id' => 'bail|required|exists:'.$this->entity.'s,id,company_id,'.auth()->user()->company()->id,
];
}
public function prepareForValidation()
{
$input = $this->all();
if(isset($input['entity_id']))
$input['entity_id'] = $this->decodePrimaryKey($input['entity_id']);
$this->replace($input);
} }
} }

View File

@ -45,7 +45,7 @@ class ShowChartRequest extends Request
$input = $this->all(); $input = $this->all();
if(isset($input['date_range'])) { if(isset($input['date_range'])) {
$dates = $this->calculateStartAndEndDates($input); $dates = $this->calculateStartAndEndDates($input, auth()->user()->company());
$input['start_date'] = $dates[0]; $input['start_date'] = $dates[0];
$input['end_date'] = $dates[1]; $input['end_date'] = $dates[1];
} }

View File

@ -67,6 +67,7 @@ class StoreCreditRequest extends Request
$rules['tax_name1'] = 'bail|sometimes|string|nullable'; $rules['tax_name1'] = 'bail|sometimes|string|nullable';
$rules['tax_name2'] = 'bail|sometimes|string|nullable'; $rules['tax_name2'] = 'bail|sometimes|string|nullable';
$rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable';
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
if ($this->invoice_id) { if ($this->invoice_id) {
$rules['invoice_id'] = new ValidInvoiceCreditRule(); $rules['invoice_id'] = new ValidInvoiceCreditRule();
@ -88,7 +89,11 @@ class StoreCreditRequest extends Request
$input = $this->decodePrimaryKeys($input); $input = $this->decodePrimaryKeys($input);
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
//$input['line_items'] = json_encode($input['line_items']);
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
$input['exchange_rate'] = 1;
}
$this->replace($input); $this->replace($input);
} }
} }

View File

@ -67,6 +67,7 @@ class UpdateCreditRequest extends Request
$rules['tax_name1'] = 'bail|sometimes|string|nullable'; $rules['tax_name1'] = 'bail|sometimes|string|nullable';
$rules['tax_name2'] = 'bail|sometimes|string|nullable'; $rules['tax_name2'] = 'bail|sometimes|string|nullable';
$rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable';
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
return $rules; return $rules;
} }
@ -81,6 +82,10 @@ class UpdateCreditRequest extends Request
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
} }
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
$input['exchange_rate'] = 1;
}
$input['id'] = $this->credit->id; $input['id'] = $this->credit->id;
$this->replace($input); $this->replace($input);

View File

@ -72,6 +72,7 @@ class StoreInvoiceRequest extends Request
$rules['tax_name1'] = 'bail|sometimes|string|nullable'; $rules['tax_name1'] = 'bail|sometimes|string|nullable';
$rules['tax_name2'] = 'bail|sometimes|string|nullable'; $rules['tax_name2'] = 'bail|sometimes|string|nullable';
$rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable';
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
return $rules; return $rules;
} }

View File

@ -72,6 +72,7 @@ class UpdateInvoiceRequest extends Request
$rules['tax_name2'] = 'bail|sometimes|string|nullable'; $rules['tax_name2'] = 'bail|sometimes|string|nullable';
$rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable';
$rules['status_id'] = 'bail|sometimes|not_in:5'; //do not all cancelled invoices to be modfified. $rules['status_id'] = 'bail|sometimes|not_in:5'; //do not all cancelled invoices to be modfified.
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
// not needed. // not needed.
// $rules['partial_due_date'] = 'bail|sometimes|required_unless:partial,0,null'; // $rules['partial_due_date'] = 'bail|sometimes|required_unless:partial,0,null';
@ -95,6 +96,10 @@ class UpdateInvoiceRequest extends Request
unset($input['documents']); unset($input['documents']);
} }
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
$input['exchange_rate'] = 1;
}
$this->replace($input); $this->replace($input);
} }

View File

@ -60,6 +60,7 @@ class StorePurchaseOrderRequest extends Request
} }
$rules['status_id'] = 'nullable|integer|in:1,2,3,4,5'; $rules['status_id'] = 'nullable|integer|in:1,2,3,4,5';
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
return $rules; return $rules;
} }
@ -77,6 +78,10 @@ class StorePurchaseOrderRequest extends Request
$input['amount'] = 0; $input['amount'] = 0;
$input['balance'] = 0; $input['balance'] = 0;
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
$input['exchange_rate'] = 1;
}
$this->replace($input); $this->replace($input);
} }
} }

View File

@ -63,6 +63,7 @@ class UpdatePurchaseOrderRequest extends Request
} }
$rules['status_id'] = 'sometimes|integer|in:1,2,3,4,5'; $rules['status_id'] = 'sometimes|integer|in:1,2,3,4,5';
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
return $rules; return $rules;
} }
@ -79,6 +80,10 @@ class UpdatePurchaseOrderRequest extends Request
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
} }
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
$input['exchange_rate'] = 1;
}
$this->replace($input); $this->replace($input);
} }
} }

View File

@ -55,6 +55,7 @@ class StoreQuoteRequest extends Request
$rules['discount'] = 'sometimes|numeric'; $rules['discount'] = 'sometimes|numeric';
$rules['is_amount_discount'] = ['boolean']; $rules['is_amount_discount'] = ['boolean'];
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
// $rules['number'] = new UniqueQuoteNumberRule($this->all()); // $rules['number'] = new UniqueQuoteNumberRule($this->all());
$rules['line_items'] = 'array'; $rules['line_items'] = 'array';
@ -72,6 +73,10 @@ class StoreQuoteRequest extends Request
$input['amount'] = 0; $input['amount'] = 0;
$input['balance'] = 0; $input['balance'] = 0;
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
$input['exchange_rate'] = 1;
}
$this->replace($input); $this->replace($input);
} }
} }

View File

@ -57,6 +57,7 @@ class UpdateQuoteRequest extends Request
$rules['line_items'] = 'array'; $rules['line_items'] = 'array';
$rules['discount'] = 'sometimes|numeric'; $rules['discount'] = 'sometimes|numeric';
$rules['is_amount_discount'] = ['boolean']; $rules['is_amount_discount'] = ['boolean'];
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
return $rules; return $rules;
} }
@ -75,6 +76,10 @@ class UpdateQuoteRequest extends Request
unset($input['documents']); unset($input['documents']);
} }
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
$input['exchange_rate'] = 1;
}
$input['id'] = $this->quote->id; $input['id'] = $this->quote->id;
$this->replace($input); $this->replace($input);

View File

@ -67,6 +67,7 @@ class StoreRecurringInvoiceRequest extends Request
$rules['tax_name2'] = 'bail|sometimes|string|nullable'; $rules['tax_name2'] = 'bail|sometimes|string|nullable';
$rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable';
$rules['due_date_days'] = 'bail|sometimes|string'; $rules['due_date_days'] = 'bail|sometimes|string';
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
return $rules; return $rules;
} }
@ -143,6 +144,10 @@ class StoreRecurringInvoiceRequest extends Request
unset($input['number']); unset($input['number']);
} }
if (array_key_exists('exchange_rate', $input) && (is_null($input['exchange_rate']) || $input['exchange_rate'] == 0)) {
$input['exchange_rate'] = 1;
}
$this->replace($input); $this->replace($input);
} }

View File

@ -61,6 +61,7 @@ class UpdateRecurringInvoiceRequest extends Request
$rules['tax_name1'] = 'bail|sometimes|string|nullable'; $rules['tax_name1'] = 'bail|sometimes|string|nullable';
$rules['tax_name2'] = 'bail|sometimes|string|nullable'; $rules['tax_name2'] = 'bail|sometimes|string|nullable';
$rules['tax_name3'] = 'bail|sometimes|string|nullable'; $rules['tax_name3'] = 'bail|sometimes|string|nullable';
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
return $rules; return $rules;
} }
@ -121,6 +122,10 @@ class UpdateRecurringInvoiceRequest extends Request
unset($input['documents']); unset($input['documents']);
} }
if (array_key_exists('exchange_rate', $input) && (is_null($input['exchange_rate']) || $input['exchange_rate'] == 0)) {
$input['exchange_rate'] = 1;
}
$this->replace($input); $this->replace($input);
} }

View File

@ -102,6 +102,8 @@ class BaseImport
} }
$csv = base64_decode($base64_encoded_csv); $csv = base64_decode($base64_encoded_csv);
$csv = mb_convert_encoding($csv, 'UTF-8', 'UTF-8');
nlog($csv);
$csv = Reader::createFromString($csv); $csv = Reader::createFromString($csv);
$csvdelimiter = self::detectDelimiter($csv); $csvdelimiter = self::detectDelimiter($csv);
@ -477,8 +479,12 @@ class BaseImport
} }
nlog($invoice_data); nlog($invoice_data);
$saveable_invoice_data = $invoice_data;
$invoice_repository->save($invoice_data, $invoice); if(array_key_exists('payments', $saveable_invoice_data))
unset($saveable_invoice_data['payments']);
$invoice_repository->save($saveable_invoice_data, $invoice);
$count++; $count++;
// If we're doing a generic CSV import, only import payment data if we're not importing a payment CSV. // If we're doing a generic CSV import, only import payment data if we're not importing a payment CSV.
@ -504,7 +510,7 @@ class BaseImport
]; ];
/* Make sure we don't apply any payments to invoices with a Zero Amount*/ /* Make sure we don't apply any payments to invoices with a Zero Amount*/
if ($invoice->amount > 0) { if ($invoice->amount > 0 && $payment_data['amount'] > 0) {
$payment = $payment_repository->save( $payment = $payment_repository->save(
$payment_data, $payment_data,

View File

@ -319,6 +319,21 @@ class BaseTransformer
// return Number::parseFloat($number); // return Number::parseFloat($number);
} }
/**
* @param $data
* @param $field
*
* @return float
*/
public function getFloatOrOne($data, $field)
{
if (array_key_exists($field, $data))
return Number::parseStringFloat($data[$field]) > 0 ? Number::parseStringFloat($data[$field]) : 1;
return 1;
}
/** /**
* @param $name * @param $name
* *

View File

@ -114,7 +114,7 @@ class InvoiceTransformer extends BaseTransformer
$invoice_data, $invoice_data,
'invoice.custom_surcharge4' 'invoice.custom_surcharge4'
), ),
'exchange_rate' => $this->getString( 'exchange_rate' => $this->getFloatOrOne(
$invoice_data, $invoice_data,
'invoice.exchange_rate' 'invoice.exchange_rate'
), ),

View File

@ -46,7 +46,7 @@ class PaymentTransformer extends BaseTransformer
$data, $data,
'payment.transaction_reference ' 'payment.transaction_reference '
), ),
'date' => $this->getString($data, 'payment.date'), 'date' => isset($data['payment.date']) ? $this->parseDate($data['payment.date']) : date('y-m-d'),
'private_notes' => $this->getString($data, 'payment.private_notes'), 'private_notes' => $this->getString($data, 'payment.private_notes'),
'custom_value1' => $this->getString($data, 'payment.custom_value1'), 'custom_value1' => $this->getString($data, 'payment.custom_value1'),
'custom_value2' => $this->getString($data, 'payment.custom_value2'), 'custom_value2' => $this->getString($data, 'payment.custom_value2'),

View File

@ -114,7 +114,7 @@ class QuoteTransformer extends BaseTransformer
$quote_data, $quote_data,
'quote.custom_surcharge4' 'quote.custom_surcharge4'
), ),
'exchange_rate' => $this->getString( 'exchange_rate' => $this->getFloatOrOne(
$quote_data, $quote_data,
'quote.exchange_rate' 'quote.exchange_rate'
), ),

View File

@ -122,7 +122,7 @@ class RecurringInvoiceTransformer extends BaseTransformer
$invoice_data, $invoice_data,
'invoice.custom_surcharge4' 'invoice.custom_surcharge4'
), ),
'exchange_rate' => $this->getString( 'exchange_rate' => $this->getFloat(
$invoice_data, $invoice_data,
'invoice.exchange_rate' 'invoice.exchange_rate'
), ),

View File

@ -24,6 +24,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\Middleware\WithoutOverlapping;
use App\Notifications\Ninja\GenericNinjaAdminNotification; use App\Notifications\Ninja\GenericNinjaAdminNotification;
use App\Helpers\Bank\Yodlee\Transformer\AccountTransformer;
class ProcessBankTransactions implements ShouldQueue class ProcessBankTransactions implements ShouldQueue
{ {
@ -99,6 +100,24 @@ class ProcessBankTransactions implements ShouldQueue
return; return;
} }
try {
$account_summary = $yodlee->getAccountSummary($this->bank_integration->bank_account_id);
if($account_summary) {
$at = new AccountTransformer();
$account = $at->transform($account_summary);
$this->bank_integration->balance = $account['current_balance'];
$this->bank_integration->currency = $account['account_currency'];
$this->bank_integration->save();
}
}
catch(\Exception $e) {
nlog("YODLEE: unable to update account summary for {$this->bank_integration->bank_account_id} => ". $e->getMessage());
}
$data = [ $data = [
'top' => 500, 'top' => 500,
'fromDate' => $this->from_date, 'fromDate' => $this->from_date,

View File

@ -441,15 +441,15 @@ class CompanyExport implements ShouldQueue
$path = 'backups'; $path = 'backups';
Storage::makeDirectory(public_path('storage/backups/')); Storage::makeDirectory(storage_path('backups/'));
try { try {
mkdir(public_path('storage/backups/')); mkdir(storage_path('backups/'));
} catch(\Exception $e) { } catch(\Exception $e) {
nlog("could not create directory"); nlog("could not create directory");
} }
$zip_path = public_path('storage/backups/'.$file_name); $zip_path = storage_path('backups/'.$file_name);
$zip = new \ZipArchive(); $zip = new \ZipArchive();
if ($zip->open($zip_path, \ZipArchive::CREATE)!==true) { if ($zip->open($zip_path, \ZipArchive::CREATE)!==true) {
@ -459,14 +459,16 @@ class CompanyExport implements ShouldQueue
$zip->addFromString("backup.json", json_encode($this->export_data)); $zip->addFromString("backup.json", json_encode($this->export_data));
$zip->close(); $zip->close();
if (Ninja::isHosted()) {
Storage::disk(config('filesystems.default'))->put('backups/'.$file_name, file_get_contents($zip_path)); Storage::disk(config('filesystems.default'))->put('backups/'.$file_name, file_get_contents($zip_path));
} unlink($zip_path);
$storage_file_path = Storage::disk(config('filesystems.default'))->url('backups/'.$file_name); if(Ninja::isSelfHost())
$storage_path = 'backups/'.$file_name;
else
$storage_path = Storage::disk(config('filesystems.default'))->path('backups/'.$file_name); $storage_path = Storage::disk(config('filesystems.default'))->path('backups/'.$file_name);
$url = Cache::get($this->hash); $url = Cache::get($this->hash);
Cache::put($this->hash, $storage_path, now()->addHour()); Cache::put($this->hash, $storage_path, now()->addHour());
App::forgetInstance('translator'); App::forgetInstance('translator');

View File

@ -398,6 +398,9 @@ class Import implements ShouldQueue
$data = $this->transformCompanyData($data); $data = $this->transformCompanyData($data);
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
$data['subdomain'] = str_replace("_","",$data['subdomain']);
if (!MultiDB::checkDomainAvailable($data['subdomain'])) { if (!MultiDB::checkDomainAvailable($data['subdomain'])) {
$data['subdomain'] = MultiDB::randomSubdomainGenerator(); $data['subdomain'] = MultiDB::randomSubdomainGenerator();
} }

View File

@ -129,12 +129,10 @@ class ReminderJob implements ShouldQueue
$invoice->service()->touchReminder($reminder_template)->save(); $invoice->service()->touchReminder($reminder_template)->save();
$fees = $this->calcLateFee($invoice, $reminder_template); $fees = $this->calcLateFee($invoice, $reminder_template);
if(in_array($invoice->client->getSetting('lock_invoices'), ['when_sent','when_paid'])) { if($invoice->isLocked())
return $this->addFeeToNewInvoice($invoice, $reminder_template, $fees); return $this->addFeeToNewInvoice($invoice, $reminder_template, $fees);
}
else
$invoice = $this->setLateFee($invoice, $fees[0], $fees[1]);
$invoice = $this->setLateFee($invoice, $fees[0], $fees[1]);
//20-04-2022 fixes for endless reminders - generic template naming was wrong //20-04-2022 fixes for endless reminders - generic template naming was wrong
$enabled_reminder = 'enable_'.$reminder_template; $enabled_reminder = 'enable_'.$reminder_template;

View File

@ -43,6 +43,10 @@ class UnlinkFile implements ShouldQueue
return; return;
} }
try {
Storage::disk($this->disk)->delete($this->file_path); Storage::disk($this->disk)->delete($this->file_path);
} catch (\Exception $e) {
}
} }
} }

View File

@ -554,7 +554,7 @@ class Account extends BaseModel
$nmo->to_user = $this->companies()->first()->owner(); $nmo->to_user = $this->companies()->first()->owner();
NinjaMailerJob::dispatch($nmo, true); NinjaMailerJob::dispatch($nmo, true);
Cache::put("throttle_notified:{$this->key}", true, 60 * 24); Cache::put("throttle_notified:{$this->key}", true, 60 * 60 * 24);
if (config('ninja.notification.slack')) { if (config('ninja.notification.slack')) {
$this->companies()->first()->notification(new EmailQuotaNotification($this))->ninja(); $this->companies()->first()->notification(new EmailQuotaNotification($this))->ninja();

View File

@ -347,6 +347,11 @@ class Client extends BaseModel implements HasLocalePreference
return $this->hasMany(Credit::class)->withTrashed(); return $this->hasMany(Credit::class)->withTrashed();
} }
public function purgeable_activities()
{
return $this->hasMany(Activity::class);
}
public function activities() public function activities()
{ {
return $this->hasMany(Activity::class)->take(50)->orderBy('id', 'desc'); return $this->hasMany(Activity::class)->take(50)->orderBy('id', 'desc');

View File

@ -16,6 +16,7 @@ use App\Casts\EncryptedCast;
use App\Utils\Traits\AppSetup; use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\DataMapper\CompanySettings; use App\DataMapper\CompanySettings;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Laracasts\Presenter\PresentableTrait; use Laracasts\Presenter\PresentableTrait;
use App\Utils\Traits\CompanySettingsSaver; use App\Utils\Traits\CompanySettingsSaver;
@ -686,6 +687,11 @@ class Company extends BaseModel
return $this->getLocale(); return $this->getLocale();
} }
public function setLocale()
{
App::setLocale($this->getLocale());
}
public function getSetting($setting) public function getSetting($setting)
{ {
if (property_exists($this->settings, $setting) != false) { if (property_exists($this->settings, $setting) != false) {

View File

@ -455,7 +455,7 @@ class Quote extends BaseModel
case self::STATUS_DRAFT: case self::STATUS_DRAFT:
return ctrans('texts.draft'); return ctrans('texts.draft');
case self::STATUS_SENT: case self::STATUS_SENT:
return ctrans('texts.pending'); return ctrans('texts.sent');
case self::STATUS_APPROVED: case self::STATUS_APPROVED:
return ctrans('texts.approved'); return ctrans('texts.approved');
case self::STATUS_EXPIRED: case self::STATUS_EXPIRED:

View File

@ -0,0 +1,122 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\PaymentDrivers\CheckoutCom;
use App\Models\Payment;
use App\Models\SystemLog;
use App\Libraries\MultiDB;
use App\Models\GatewayType;
use App\Models\PaymentHash;
use App\Models\PaymentType;
use Illuminate\Bus\Queueable;
use App\Models\CompanyGateway;
use App\Jobs\Util\SystemLogger;
use Checkout\CheckoutApiException;
use Illuminate\Queue\SerializesModels;
use App\PaymentDrivers\Stripe\Utilities;
use Illuminate\Queue\InteractsWithQueue;
use App\PaymentDrivers\CheckoutCom\Webhook;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Checkout\CheckoutAuthorizationException;
use Checkout\Workflows\CreateWorkflowRequest;
use App\PaymentDrivers\CheckoutComPaymentDriver;
use Checkout\Workflows\Actions\WebhookSignature;
use Checkout\Workflows\Actions\WebhookWorkflowActionRequest;
use Checkout\Workflows\Conditions\EventWorkflowConditionRequest;
class CheckoutSetupWebhook implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Utilities;
public $tries = 1;
public $deleteWhenMissingModels = true;
private string $authentication_webhook_name = 'Invoice_Ninja_3DS_Workflow';
public CheckoutComPaymentDriver $checkout;
public function __construct(private string $company_key, private int $company_gateway_id)
{
}
public function handle()
{
MultiDB::findAndSetDbByCompanyKey($this->company_key);
$company_gateway = CompanyGateway::find($this->company_gateway_id);
$this->checkout = $company_gateway->driver()->init();
$webhook = new Webhook($this->checkout);
$workflows = $webhook->getWorkFlows();
$wf = collect($workflows['data'])->first(function ($workflow) {
return $workflow['name'] == $this->authentication_webhook_name;
});
if($wf)
return;
$this->createAuthenticationWorkflow();
}
/**
* Creates an authentication workflow for 3DS
* and also a registration mechanism for payments that have been approved.
*
* @return void
*/
public function createAuthenticationWorkflow()
{
$signature = new WebhookSignature();
$signature->key = $this->checkout->company_gateway->company->company_key;
$signature->method = "HMACSHA256";
$actionRequest = new WebhookWorkflowActionRequest();
$actionRequest->url = $this->checkout->company_gateway->webhookUrl();
$actionRequest->signature = $signature;
$eventWorkflowConditionRequest = new EventWorkflowConditionRequest();
$eventWorkflowConditionRequest->events = [
"gateway" => ["payment_approved"],
"issuing" => ["authorization_approved","authorization_declined"],
];
$request = new CreateWorkflowRequest();
$request->actions = [$actionRequest];
$request->conditions = [$eventWorkflowConditionRequest];
$request->name = $this->authentication_webhook_name;
$request->active = true;
try {
$response = $this->checkout->gateway->getWorkflowsClient()->createWorkflow($request);
} catch (CheckoutApiException $e) {
// API error
$error_details = $e->error_details;
$http_status_code = isset($e->http_metadata) ? $e->http_metadata->getStatusCode() : null;
nlog("Checkout WEBHOOK creation error");
nlog($error_details);
} catch (CheckoutAuthorizationException $e) {
// Bad Invalid authorization
}
}
}

View File

@ -0,0 +1,117 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\PaymentDrivers\CheckoutCom;
use App\Models\Payment;
use App\Models\SystemLog;
use App\Libraries\MultiDB;
use App\Models\GatewayType;
use App\Models\PaymentHash;
use App\Models\PaymentType;
use Illuminate\Bus\Queueable;
use App\Models\CompanyGateway;
use App\Jobs\Util\SystemLogger;
use Illuminate\Queue\SerializesModels;
use App\PaymentDrivers\Stripe\Utilities;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class CheckoutWebhook implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Utilities;
public $tries = 1;
public $deleteWhenMissingModels = true;
public CompanyGateway $company_gateway;
public function __construct(public array $webhook_array, public string $company_key, public int $company_gateway_id)
{
}
public function handle()
{
nlog("Checkout Webhook");
MultiDB::findAndSetDbByCompanyKey($this->company_key);
$this->company_gateway = CompanyGateway::withTrashed()->find($this->company_gateway_id);
if(!isset($this->webhook_array['type']))
nlog("Checkout Webhook type not set");
match($this->webhook_array['type']){
'payment_approved' => $this->paymentApproved(),
};
}
/**
* {
* "id":"evt_dli6ty4qo5vuxle5wklf5gwbwy","type":"payment_approved","version":"1.0.33","created_on":"2023-07-21T10:03:07.1555904Z",
* "data":{"id":"pay_oqwbsd22kvpuvd35y5fhbdawxa","action_id":"act_buviezur7zsurnsorcgfn63e44","reference":"0014","amount":584168,"auth_code":"113059","currency":"USD","customer":{"id":"cus_6n4yt4q5kf4unn36o5qpbevxhe","email":"cypress@example.com"},
* "metadata":{"udf1":"Invoice Ninja","udf2":"ofhgiGjyQXbsbUwygURfYFT2C3E7iY7U"},"payment_type":"Regular","processed_on":"2023-07-21T10:02:57.4678165Z","processing":{"acquirer_transaction_id":"645272142084717830381","retrieval_reference_number":"183042259107"},"response_code":"10000","response_summary":"Approved","risk":{"flagged":false,"score":0},"3ds":{"version":"2.2.0","challenged":true,"challenge_indicator":"no_preference","exemption":"none","eci":"05","cavv":"AAABAVIREQAAAAAAAAAAAAAAAAA=","xid":"74afa3ac-25d3-4d95-b815-cefbdd7c8270","downgraded":false,"enrolled":"Y","authentication_response":"Y","flow_type":"challenged"},"scheme_id":"114455763095262",
* "source":{"id":"src_ghavmefpetjellmteqwj5jjcli","type":"card","billing_address":{},"expiry_month":10,"expiry_year":2025,"scheme":"VISA","last_4":"4242","fingerprint":"BD864B08D0B098DD83052A038FD2BA967DF2D48E375AAEEF54E37BC36B385E9A","bin":"424242","card_type":"CREDIT","card_category":"CONSUMER","issuer_country":"GB","product_id":"F","product_type":"Visa Classic","avs_check":"G","cvv_check":"Y"},"balances":{"total_authorized":584168,"total_voided":0,"available_to_void":584168,"total_captured":0,"available_to_capture":584168,"total_refunded":0,"available_to_refund":0},"event_links":{"payment":"https://api.sandbox.checkout.com/payments/pay_oqwbsd22kvpuvd35y5fhbdawxa","payment_actions":"https://api.sandbox.checkout.com/payments/pay_oqwbsd22kvpuvd35y5fhbdawxa/actions","capture":"https://api.sandbox.checkout.com/payments/pay_oqwbsd22kvpuvd35y5fhbdawxa/captures","void":"https://api.sandbox.checkout.com/payments/pay_oqwbsd22kvpuvd35y5fhbdawxa/voids"}},"_links":{"self":{"href":"https://api.sandbox.checkout.com/workflows/events/evt_dli6ty4qo5vuxle5wklf5gwbwy"},"subject":{"href":"https://api.sandbox.checkout.com/workflows/events/subject/pay_oqwbsd22kvpuvd35y5fhbdawxa"},"payment":{"href":"https://api.sandbox.checkout.com/payments/pay_oqwbsd22kvpuvd35y5fhbdawxa"},"payment_actions":{"href":"https://api.sandbox.checkout.com/payments/pay_oqwbsd22kvpuvd35y5fhbdawxa/actions"},"capture":{"href":"https://api.sandbox.checkout.com/payments/pay_oqwbsd22kvpuvd35y5fhbdawxa/captures"},"void":{"href":"https://api.sandbox.checkout.com/payments/pay_oqwbsd22kvpuvd35y5fhbdawxa/voids"}}}
*/
private function paymentApproved()
{
$payment_object = $this->webhook_array['data'];
$payment = Payment::withTrashed()->where('transaction_reference', $payment_object['id'])->first();
if($payment && $payment->status_id == Payment::STATUS_COMPLETED)
return;
if($payment){
$payment->status_id = Payment::STATUS_COMPLETED;
$payment->save();
return;
}
if(isset($this->webhook_array['metadata'])) {
$metadata = $this->webhook_array['metadata'];
$payment_hash = PaymentHash::where('hash', $metadata['udf2'])->first();
$driver = $this->company_gateway->driver($payment_hash->fee_invoice->client)->init()->setPaymentMethod();
$payment_hash->data = array_merge((array) $payment_hash->data, $this->webhook_array);
$payment_hash->save();
$driver->setPaymentHash($payment_hash);
$data = [
'payment_method' => isset($this->webhook_array['source']['id']) ? $this->webhook_array['source']['id'] : '',
'payment_type' => PaymentType::CREDIT_CARD_OTHER,
'amount' => $payment_hash->data->raw_value,
'transaction_reference' => $payment_object['id'],
'gateway_type_id' => GatewayType::CREDIT_CARD,
];
$payment = $driver->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => $this->webhook_array, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_CHECKOUT,
$payment_hash->fee_invoice->client,
$this->company_gateway->company,
);
}
}
}

View File

@ -228,7 +228,7 @@ class CreditCard implements MethodInterface
$paymentRequest->amount = $this->checkout->payment_hash->data->value; $paymentRequest->amount = $this->checkout->payment_hash->data->value;
$paymentRequest->reference = substr($this->checkout->getDescription(), 0, 49); $paymentRequest->reference = substr($this->checkout->getDescription(), 0, 49);
$paymentRequest->customer = $this->checkout->getCustomer(); $paymentRequest->customer = $this->checkout->getCustomer();
$paymentRequest->metadata = ['udf1' => 'Invoice Ninja']; $paymentRequest->metadata = ['udf1' => 'Invoice Ninja', 'udf2' => $this->checkout->payment_hash->hash];
$paymentRequest->currency = $this->checkout->client->getCurrencyCode(); $paymentRequest->currency = $this->checkout->client->getCurrencyCode();
$this->checkout->payment_hash->data = array_merge((array) $this->checkout->payment_hash->data, ['checkout_payment_ref' => $paymentRequest]); $this->checkout->payment_hash->data = array_merge((array) $this->checkout->payment_hash->data, ['checkout_payment_ref' => $paymentRequest]);

View File

@ -12,12 +12,13 @@
namespace App\PaymentDrivers\CheckoutCom; namespace App\PaymentDrivers\CheckoutCom;
use App\Exceptions\PaymentFailed;
use App\Jobs\Util\SystemLogger;
use App\Models\GatewayType;
use App\Models\SystemLog;
use Exception;
use stdClass; use stdClass;
use Exception;
use App\Models\SystemLog;
use App\Models\GatewayType;
use App\Jobs\Util\SystemLogger;
use App\Exceptions\PaymentFailed;
use Checkout\Payments\PaymentType;
trait Utilities trait Utilities
{ {
@ -60,7 +61,7 @@ trait Utilities
$data = [ $data = [
'payment_method' => $_payment['source']['id'], 'payment_method' => $_payment['source']['id'],
'payment_type' => 12, 'payment_type' => \App\Models\PaymentType::CREDIT_CARD_OTHER,
'amount' => $this->getParent()->payment_hash->data->raw_value, 'amount' => $this->getParent()->payment_hash->data->raw_value,
'transaction_reference' => $_payment['id'], 'transaction_reference' => $_payment['id'],
'gateway_type_id' => GatewayType::CREDIT_CARD, 'gateway_type_id' => GatewayType::CREDIT_CARD,

View File

@ -0,0 +1,91 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\PaymentDrivers\CheckoutCom;
use App\Exceptions\PaymentFailed;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\Jobs\Util\SystemLogger;
use App\Models\ClientGatewayToken;
use App\Models\GatewayType;
use App\Models\SystemLog;
use App\PaymentDrivers\CheckoutComPaymentDriver;
use App\PaymentDrivers\Common\MethodInterface;
use App\Utils\Traits\MakesHash;
use Checkout\CheckoutApiException;
use Checkout\CheckoutArgumentException;
use Checkout\CheckoutAuthorizationException;
use Checkout\Payments\Four\Request\PaymentRequest;
use Checkout\Payments\Four\Request\Source\RequestTokenSource;
use Checkout\Payments\PaymentRequest as PaymentsPaymentRequest;
use Checkout\Payments\Source\RequestTokenSource as SourceRequestTokenSource;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request;
use Illuminate\View\View;
class Webhook
{
public function __construct(public CheckoutComPaymentDriver $checkout)
{
$this->checkout = $checkout;
}
/**
* Lists all possible events in checkout and a brief description
*
* @return void
*/
public function getEventTypes()
{
try {
$response = $this->checkout->gateway->getWorkflowsClient()->getEventTypes();
return $response;
} catch (CheckoutApiException $e) {
// API error
$error_details = $e->error_details;
nlog($error_details);
$http_status_code = isset($e->http_metadata) ? $e->http_metadata->getStatusCode() : null;
} catch (CheckoutAuthorizationException $e) {
// Bad Invalid authorization
}
}
/**
* Lists the workflows in Checkout
*
* @return void
*/
public function getWorkFlows()
{
try {
$response = $this->checkout->gateway->getWorkflowsClient()->getWorkflows();
return $response;
} catch (CheckoutApiException $e) {
// API error
$error_details = $e->error_details;
$http_status_code = isset($e->http_metadata) ? $e->http_metadata->getStatusCode() : null;
} catch (CheckoutAuthorizationException $e) {
// Bad Invalid authorization
}
}
}

View File

@ -27,6 +27,7 @@ use App\Models\PaymentType;
use App\Models\SystemLog; use App\Models\SystemLog;
use App\PaymentDrivers\CheckoutCom\CreditCard; use App\PaymentDrivers\CheckoutCom\CreditCard;
use App\PaymentDrivers\CheckoutCom\Utilities; use App\PaymentDrivers\CheckoutCom\Utilities;
use App\PaymentDrivers\CheckoutCom\CheckoutWebhook;
use App\Utils\Traits\SystemLogTrait; use App\Utils\Traits\SystemLogTrait;
use Checkout\CheckoutApi; use Checkout\CheckoutApi;
use Checkout\CheckoutApiException; use Checkout\CheckoutApiException;
@ -334,7 +335,7 @@ class CheckoutComPaymentDriver extends BaseDriver
$paymentRequest->amount = $this->convertToCheckoutAmount($amount, $this->client->getCurrencyCode()); $paymentRequest->amount = $this->convertToCheckoutAmount($amount, $this->client->getCurrencyCode());
$paymentRequest->reference = '#'.$invoice->number.' - '.now(); $paymentRequest->reference = '#'.$invoice->number.' - '.now();
$paymentRequest->customer = $this->getCustomer(); $paymentRequest->customer = $this->getCustomer();
$paymentRequest->metadata = ['udf1' => 'Invoice Ninja']; $paymentRequest->metadata = ['udf1' => 'Invoice Ninja', 'udf2' => $payment_hash->hash];
$paymentRequest->currency = $this->client->getCurrencyCode(); $paymentRequest->currency = $this->client->getCurrencyCode();
$request = new PaymentResponseRequest(); $request = new PaymentResponseRequest();
@ -421,7 +422,19 @@ class CheckoutComPaymentDriver extends BaseDriver
public function processWebhookRequest(PaymentWebhookRequest $request) public function processWebhookRequest(PaymentWebhookRequest $request)
{ {
return true;
header('Content-Type: text/plain');
$webhook_payload = file_get_contents('php://input');
if($request->header('cko-signature') == hash_hmac('sha256', $webhook_payload, $this->company_gateway->company->company_key)) {
CheckoutWebhook::dispatch($request->all(), $request->company_key, $this->company_gateway->id)->delay(10);
}
else {
nlog("Hash Mismatch = {$request->header('cko-signature')} ".hash_hmac('sha256', $webhook_payload, $this->company_gateway->company->company_key));
nlog($request->all());
}
return response()->json(['success' => true]);
} }
public function process3dsConfirmation(Checkout3dsRequest $request) public function process3dsConfirmation(Checkout3dsRequest $request)
@ -440,6 +453,9 @@ class CheckoutComPaymentDriver extends BaseDriver
$request->query('cko-session-id') $request->query('cko-session-id')
); );
nlog("checkout3ds");
nlog($payment);
if (isset($payment['approved']) && $payment['approved']) { if (isset($payment['approved']) && $payment['approved']) {
return $this->processSuccessfulPayment($payment); return $this->processSuccessfulPayment($payment);
} else { } else {

View File

@ -136,7 +136,7 @@ class ClientRepository extends BaseRepository
$client->projects()->forceDelete(); $client->projects()->forceDelete();
$client->credits()->forceDelete(); $client->credits()->forceDelete();
$client->quotes()->forceDelete(); $client->quotes()->forceDelete();
$client->activities()->forceDelete(); $client->purgeable_activities()->forceDelete();
$client->recurring_invoices()->forceDelete(); $client->recurring_invoices()->forceDelete();
$client->expenses()->forceDelete(); $client->expenses()->forceDelete();
$client->recurring_expenses()->forceDelete(); $client->recurring_expenses()->forceDelete();

View File

@ -97,6 +97,10 @@ class InvoiceRepository extends BaseRepository
// reversed delete invoice actions // reversed delete invoice actions
$invoice = $invoice->service()->handleRestore()->save(); $invoice = $invoice->service()->handleRestore()->save();
/* If the reverse did not succeed due to rules, then do not restore / unarchive */
if($invoice->is_deleted)
return $invoice;
parent::restore($invoice); parent::restore($invoice);
return $invoice; return $invoice;

View File

@ -101,9 +101,6 @@ class TaskRepository extends BaseRepository
$key_values = array_column($time_log, 0); $key_values = array_column($time_log, 0);
array_multisort($key_values, SORT_ASC, $time_log); array_multisort($key_values, SORT_ASC, $time_log);
// array_multisort($time_log);
// ksort($time_log);
if (isset($data['action'])) { if (isset($data['action'])) {
if ($data['action'] == 'start') { if ($data['action'] == 'start') {
$task->is_running = true; $task->is_running = true;
@ -121,8 +118,12 @@ class TaskRepository extends BaseRepository
$task->is_running = $data['is_running'] ? 1 : 0; $task->is_running = $data['is_running'] ? 1 : 0;
} }
$task->calculated_start_date = $this->harvestStartDate($time_log);
$task->time_log = json_encode($time_log); $task->time_log = json_encode($time_log);
$task->saveQuietly(); $task->saveQuietly();
if (array_key_exists('documents', $data)) { if (array_key_exists('documents', $data)) {
@ -132,6 +133,17 @@ class TaskRepository extends BaseRepository
return $task; return $task;
} }
private function harvestStartDate($time_log)
{
if(isset($time_log[0][0])){
return \Carbon\Carbon::createFromTimestamp($time_log[0][0]);
}
return null;
}
/** /**
* Store tasks in bulk. * Store tasks in bulk.
* *
@ -199,8 +211,12 @@ class TaskRepository extends BaseRepository
if (strlen($task->time_log) < 5) { if (strlen($task->time_log) < 5) {
$log = []; $log = [];
$log = array_merge($log, [[time(), 0]]); $start_time = time();
$log = array_merge($log, [[$start_time, 0]]);
$task->time_log = json_encode($log); $task->time_log = json_encode($log);
$task->calculated_start_date = \Carbon\Carbon::createFromTimestamp($start_time);
$task->saveQuietly(); $task->saveQuietly();
} }

View File

@ -43,7 +43,13 @@ class VendorRepository extends BaseRepository
*/ */
public function save(array $data, Vendor $vendor) : ?Vendor public function save(array $data, Vendor $vendor) : ?Vendor
{ {
$vendor->fill($data); $saveable_vendor = $data;
if(array_key_exists('contacts', $data)) {
unset($saveable_vendor['contacts']);
}
$vendor->fill($saveable_vendor);
$vendor->saveQuietly(); $vendor->saveQuietly();

View File

@ -212,9 +212,9 @@ class FacturaEInvoice extends AbstractService
private function setPoNumber(): self private function setPoNumber(): self
{ {
if(strlen($this->invoice->po_number) > 1) { $po = $this->invoice->po_number ?? '';
$this->fac->setReferences($this->invoice->po_number);
} $this->fac->setReferences($po, $this->invoice->custom_value1, $this->invoice->custom_value2);
return $this; return $this;
} }
@ -233,10 +233,10 @@ class FacturaEInvoice extends AbstractService
foreach($this->invoice->line_items as $item) { foreach($this->invoice->line_items as $item) {
$this->fac->addItem(new FacturaeItem([ $this->fac->addItem(new FacturaeItem([
'name' => $item->product_key, 'name' => $item->notes,
'description' => $item->notes, 'description' => $item->product_key,
'quantity' => $item->quantity, 'quantity' => $item->quantity,
'unitPrice' => $item->cost, 'unitPriceWithoutTax' => $item->cost,
'discountsAndRebates' => $item->discount, 'discountsAndRebates' => $item->discount,
'charges' => [], 'charges' => [],
'discounts' => [], 'discounts' => [],

View File

@ -44,6 +44,7 @@ class HandleRestore extends AbstractService
//cannot restore an invoice with a deleted payment //cannot restore an invoice with a deleted payment
foreach ($this->invoice->payments as $payment) { foreach ($this->invoice->payments as $payment) {
if (($this->invoice->paid_to_date == 0) && $payment->is_deleted) { if (($this->invoice->paid_to_date == 0) && $payment->is_deleted) {
$this->invoice->delete();
return $this->invoice; return $this->invoice;
} }
} }

View File

@ -148,7 +148,7 @@ class DeletePayment
$client $client
->service() ->service()
->updatePaidToDate(($paymentable_credit->pivot->amount) * -1) // ->updatePaidToDate(($paymentable_credit->pivot->amount) * -1)
->adjustCreditBalance($paymentable_credit->pivot->amount) ->adjustCreditBalance($paymentable_credit->pivot->amount)
->save(); ->save();
}); });

View File

@ -11,11 +11,11 @@
namespace App\Services\PurchaseOrder; namespace App\Services\PurchaseOrder;
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Models\VendorContact; use App\Models\VendorContact;
use App\Services\AbstractService; use App\Services\AbstractService;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
class GetPurchaseOrderPdf extends AbstractService class GetPurchaseOrderPdf extends AbstractService
{ {
@ -31,6 +31,7 @@ class GetPurchaseOrderPdf extends AbstractService
$invitation = $this->purchase_order->invitations()->where('vendor_contact_id', $this->contact->id)->first(); $invitation = $this->purchase_order->invitations()->where('vendor_contact_id', $this->contact->id)->first();
if (! $invitation) { if (! $invitation) {
$invitation = $this->purchase_order->invitations()->first(); $invitation = $this->purchase_order->invitations()->first();
} }

View File

@ -150,7 +150,7 @@ class ClientTransformer extends EntityTransformer
'has_valid_vat_number' => (bool) $client->has_valid_vat_number, 'has_valid_vat_number' => (bool) $client->has_valid_vat_number,
'is_tax_exempt' => (bool) $client->is_tax_exempt, 'is_tax_exempt' => (bool) $client->is_tax_exempt,
'routing_id' => (string) $client->routing_id, 'routing_id' => (string) $client->routing_id,
'tax_data' => $client->tax_data ?: '', 'tax_info' => $client->tax_data ?: new \stdClass,
]; ];
} }
} }

View File

@ -133,7 +133,7 @@ class CompanyTransformer extends EntityTransformer
'show_product_details' => (bool) $company->show_product_details, 'show_product_details' => (bool) $company->show_product_details,
'enable_product_quantity' => (bool) $company->enable_product_quantity, 'enable_product_quantity' => (bool) $company->enable_product_quantity,
'default_quantity' => (bool) $company->default_quantity, 'default_quantity' => (bool) $company->default_quantity,
'custom_fields' => $company->custom_fields ?? $std, 'custom_fields' => (object) $company->custom_fields ?? $std,
'size_id' => (string) $company->size_id ?: '', 'size_id' => (string) $company->size_id ?: '',
'industry_id' => (string) $company->industry_id ?: '', 'industry_id' => (string) $company->industry_id ?: '',
'first_month_of_year' => (string) $company->first_month_of_year ?: '', 'first_month_of_year' => (string) $company->first_month_of_year ?: '',

View File

@ -149,7 +149,7 @@ class InvoiceTransformer extends EntityTransformer
'paid_to_date' => (float) $invoice->paid_to_date, 'paid_to_date' => (float) $invoice->paid_to_date,
'subscription_id' => $this->encodePrimaryKey($invoice->subscription_id), 'subscription_id' => $this->encodePrimaryKey($invoice->subscription_id),
'auto_bill_enabled' => (bool) $invoice->auto_bill_enabled, 'auto_bill_enabled' => (bool) $invoice->auto_bill_enabled,
'tax_data' => $invoice->tax_data ?: '', 'tax_info' => $invoice->tax_data ?: new \stdClass,
]; ];
} }
} }

View File

@ -37,6 +37,7 @@ class TaskTransformer extends EntityTransformer
'status', 'status',
'project', 'project',
'user', 'user',
'invoice',
]; ];
public function includeDocuments(Task $task) public function includeDocuments(Task $task)
@ -46,6 +47,17 @@ class TaskTransformer extends EntityTransformer
return $this->includeCollection($task->documents, $transformer, Document::class); return $this->includeCollection($task->documents, $transformer, Document::class);
} }
public function includeInvoice(Task $task): ?Item
{
$transformer = new InvoiceTransformer($this->serializer);
if (!$task->user) {
return null;
}
return $this->includeItem($task->invoice, $transformer, Invoice::class);
}
public function includeUser(Task $task): ?Item public function includeUser(Task $task): ?Item
{ {
$transformer = new UserTransformer($this->serializer); $transformer = new UserTransformer($this->serializer);
@ -118,6 +130,7 @@ class TaskTransformer extends EntityTransformer
'status_sort_order' => (int) $task->status_sort_order, //deprecated 5.0.34 'status_sort_order' => (int) $task->status_sort_order, //deprecated 5.0.34
'is_date_based' => (bool) $task->is_date_based, 'is_date_based' => (bool) $task->is_date_based,
'status_order' => is_null($task->status_order) ? null : (int) $task->status_order, 'status_order' => is_null($task->status_order) ? null : (int) $task->status_order,
'date' => $task->calculated_start_date ?: '',
]; ];
} }
} }

View File

@ -583,8 +583,11 @@ class HtmlEngine
if ($this->settings->signature_on_pdf) { if ($this->settings->signature_on_pdf) {
$data['$contact.signature'] = ['value' => $this->invitation->signature_base64, 'label' => ctrans('texts.signature')]; $data['$contact.signature'] = ['value' => $this->invitation->signature_base64, 'label' => ctrans('texts.signature')];
$data['$contact.signature_date'] = ['value' => $this->translateDate($this->invitation->signature_date, $this->client->date_format(), $this->client->locale()), 'label' => ctrans('texts.date')];
} else { } else {
$data['$contact.signature'] = ['value' => '', 'label' => '']; $data['$contact.signature'] = ['value' => '', 'label' => ''];
$data['$contact.signature_date'] = ['value' => '', 'label' => ctrans('texts.date')];
} }
$data['$thanks'] = ['value' => '', 'label' => ctrans('texts.thanks')]; $data['$thanks'] = ['value' => '', 'label' => ctrans('texts.thanks')];

View File

@ -14,6 +14,7 @@ namespace App\Utils\Traits;
use DateTime; use DateTime;
use DateTimeZone; use DateTimeZone;
use Carbon\Carbon; use Carbon\Carbon;
use App\Models\Company;
use App\DataMapper\Schedule\EmailStatement; use App\DataMapper\Schedule\EmailStatement;
/** /**
@ -119,8 +120,32 @@ trait MakesDates
* *
* @return array [$start_date, $end_date]; * @return array [$start_date, $end_date];
*/ */
public function calculateStartAndEndDates(array $data): array public function calculateStartAndEndDates(array $data, ?Company $company = null): array
{ {
//override for financial years
if($data['date_range'] == 'this_year') {
$first_month_of_year = $company ? $company?->first_month_of_year : 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
if(now()->lt($fin_year_start))
$fin_year_start->subYearNoOverflow();
}
//override for financial years
if($data['date_range'] == 'last_year') {
$first_month_of_year = $company ? $company?->first_month_of_year : 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
$fin_year_start->subYearNoOverflow();
if(now()->subYear()->lt($fin_year_start)) {
$fin_year_start->subYearNoOverflow();
}
}
return match ($data['date_range']) { return match ($data['date_range']) {
EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
@ -129,8 +154,8 @@ trait MakesDates
EmailStatement::LAST_MONTH => [now()->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')], EmailStatement::LAST_MONTH => [now()->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
EmailStatement::THIS_QUARTER => [now()->startOfDay()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->lastOfQuarter()->format('Y-m-d')], EmailStatement::THIS_QUARTER => [now()->startOfDay()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->lastOfQuarter()->format('Y-m-d')],
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')], EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')],
EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')], EmailStatement::THIS_YEAR => [$fin_year_start->format('Y-m-d'), $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d')],
EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')], EmailStatement::LAST_YEAR => [$fin_year_start->format('Y-m-d'), $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d')],
EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']], EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']],
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')], default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
}; };

146
composer.lock generated
View File

@ -424,16 +424,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.275.7", "version": "3.276.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "54dcef3349c81b46c0f5f6e54b5f9bfb5db19903" "reference": "78c9510280512121e8fdaa9538b744778ab48bf9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/54dcef3349c81b46c0f5f6e54b5f9bfb5db19903", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/78c9510280512121e8fdaa9538b744778ab48bf9",
"reference": "54dcef3349c81b46c0f5f6e54b5f9bfb5db19903", "reference": "78c9510280512121e8fdaa9538b744778ab48bf9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -513,9 +513,9 @@
"support": { "support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues", "issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.275.7" "source": "https://github.com/aws/aws-sdk-php/tree/3.276.2"
}, },
"time": "2023-07-13T18:21:04+00:00" "time": "2023-07-20T18:16:37+00:00"
}, },
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@ -2167,16 +2167,16 @@
}, },
{ {
"name": "firebase/php-jwt", "name": "firebase/php-jwt",
"version": "v6.8.0", "version": "v6.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/firebase/php-jwt.git", "url": "https://github.com/firebase/php-jwt.git",
"reference": "48b0210c51718d682e53210c24d25c5a10a2299b" "reference": "5dbc8959427416b8ee09a100d7a8588c00fb2e26"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/48b0210c51718d682e53210c24d25c5a10a2299b", "url": "https://api.github.com/repos/firebase/php-jwt/zipball/5dbc8959427416b8ee09a100d7a8588c00fb2e26",
"reference": "48b0210c51718d682e53210c24d25c5a10a2299b", "reference": "5dbc8959427416b8ee09a100d7a8588c00fb2e26",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2224,9 +2224,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/firebase/php-jwt/issues", "issues": "https://github.com/firebase/php-jwt/issues",
"source": "https://github.com/firebase/php-jwt/tree/v6.8.0" "source": "https://github.com/firebase/php-jwt/tree/v6.8.1"
}, },
"time": "2023-06-20T16:45:35+00:00" "time": "2023-07-14T18:33:00+00:00"
}, },
{ {
"name": "fruitcake/php-cors", "name": "fruitcake/php-cors",
@ -2485,16 +2485,16 @@
}, },
{ {
"name": "google/apiclient-services", "name": "google/apiclient-services",
"version": "v0.308.0", "version": "v0.309.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/googleapis/google-api-php-client-services.git", "url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "85cf00383e6bf6eca131bd3261b7859ea418a578" "reference": "562f8e5ddbca68d52afc3bf47d03839e78722026"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/85cf00383e6bf6eca131bd3261b7859ea418a578", "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/562f8e5ddbca68d52afc3bf47d03839e78722026",
"reference": "85cf00383e6bf6eca131bd3261b7859ea418a578", "reference": "562f8e5ddbca68d52afc3bf47d03839e78722026",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2523,9 +2523,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/googleapis/google-api-php-client-services/issues", "issues": "https://github.com/googleapis/google-api-php-client-services/issues",
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.308.0" "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.309.0"
}, },
"time": "2023-07-09T01:06:13+00:00" "time": "2023-07-16T01:08:14+00:00"
}, },
{ {
"name": "google/auth", "name": "google/auth",
@ -4554,16 +4554,16 @@
}, },
{ {
"name": "laravel/socialite", "name": "laravel/socialite",
"version": "v5.7.0", "version": "v5.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/socialite.git", "url": "https://github.com/laravel/socialite.git",
"reference": "f5996f499e14db15407201a6bfbaba3ce6ce736c" "reference": "50148edf24b6cd3e428aa9bc06a5d915b24376bb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/socialite/zipball/f5996f499e14db15407201a6bfbaba3ce6ce736c", "url": "https://api.github.com/repos/laravel/socialite/zipball/50148edf24b6cd3e428aa9bc06a5d915b24376bb",
"reference": "f5996f499e14db15407201a6bfbaba3ce6ce736c", "reference": "50148edf24b6cd3e428aa9bc06a5d915b24376bb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4620,7 +4620,7 @@
"issues": "https://github.com/laravel/socialite/issues", "issues": "https://github.com/laravel/socialite/issues",
"source": "https://github.com/laravel/socialite" "source": "https://github.com/laravel/socialite"
}, },
"time": "2023-07-08T20:51:43+00:00" "time": "2023-07-14T14:22:58+00:00"
}, },
{ {
"name": "laravel/tinker", "name": "laravel/tinker",
@ -5716,16 +5716,16 @@
}, },
{ {
"name": "microsoft/microsoft-graph", "name": "microsoft/microsoft-graph",
"version": "1.102.0", "version": "1.103.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/microsoftgraph/msgraph-sdk-php.git", "url": "https://github.com/microsoftgraph/msgraph-sdk-php.git",
"reference": "4b450b06ac9df3868bbdbddb31bfcc4595f643bc" "reference": "6e325c22145dbed4e51970ffecca4d7648c3c27e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/4b450b06ac9df3868bbdbddb31bfcc4595f643bc", "url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/6e325c22145dbed4e51970ffecca4d7648c3c27e",
"reference": "4b450b06ac9df3868bbdbddb31bfcc4595f643bc", "reference": "6e325c22145dbed4e51970ffecca4d7648c3c27e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5762,22 +5762,22 @@
"homepage": "https://developer.microsoft.com/en-us/graph", "homepage": "https://developer.microsoft.com/en-us/graph",
"support": { "support": {
"issues": "https://github.com/microsoftgraph/msgraph-sdk-php/issues", "issues": "https://github.com/microsoftgraph/msgraph-sdk-php/issues",
"source": "https://github.com/microsoftgraph/msgraph-sdk-php/tree/1.102.0" "source": "https://github.com/microsoftgraph/msgraph-sdk-php/tree/1.103.0"
}, },
"time": "2023-07-05T13:07:19+00:00" "time": "2023-07-19T03:27:15+00:00"
}, },
{ {
"name": "mollie/mollie-api-php", "name": "mollie/mollie-api-php",
"version": "v2.58.0", "version": "v2.59.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/mollie/mollie-api-php.git", "url": "https://github.com/mollie/mollie-api-php.git",
"reference": "5120e5b3e4622a290b64acf87266ea47d10d7301" "reference": "9834e5779c695d1cc278b2c78ee514de9434b084"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/5120e5b3e4622a290b64acf87266ea47d10d7301", "url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/9834e5779c695d1cc278b2c78ee514de9434b084",
"reference": "5120e5b3e4622a290b64acf87266ea47d10d7301", "reference": "9834e5779c695d1cc278b2c78ee514de9434b084",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5854,9 +5854,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/mollie/mollie-api-php/issues", "issues": "https://github.com/mollie/mollie-api-php/issues",
"source": "https://github.com/mollie/mollie-api-php/tree/v2.58.0" "source": "https://github.com/mollie/mollie-api-php/tree/v2.59.0"
}, },
"time": "2023-07-11T12:01:27+00:00" "time": "2023-07-18T13:41:40+00:00"
}, },
{ {
"name": "moneyphp/money", "name": "moneyphp/money",
@ -8514,16 +8514,16 @@
}, },
{ {
"name": "psy/psysh", "name": "psy/psysh",
"version": "v0.11.18", "version": "v0.11.19",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/bobthecow/psysh.git", "url": "https://github.com/bobthecow/psysh.git",
"reference": "4f00ee9e236fa6a48f4560d1300b9c961a70a7ec" "reference": "1724ceff278daeeac5a006744633bacbb2dc4706"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/4f00ee9e236fa6a48f4560d1300b9c961a70a7ec", "url": "https://api.github.com/repos/bobthecow/psysh/zipball/1724ceff278daeeac5a006744633bacbb2dc4706",
"reference": "4f00ee9e236fa6a48f4560d1300b9c961a70a7ec", "reference": "1724ceff278daeeac5a006744633bacbb2dc4706",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -8584,9 +8584,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/bobthecow/psysh/issues", "issues": "https://github.com/bobthecow/psysh/issues",
"source": "https://github.com/bobthecow/psysh/tree/v0.11.18" "source": "https://github.com/bobthecow/psysh/tree/v0.11.19"
}, },
"time": "2023-05-23T02:31:11+00:00" "time": "2023-07-15T19:42:19+00:00"
}, },
{ {
"name": "pusher/pusher-php-server", "name": "pusher/pusher-php-server",
@ -15188,16 +15188,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.21.1", "version": "v3.22.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "229b55b3eae4729a8e2a321441ba40fcb3720b86" "reference": "92b019f6c8d79aa26349d0db7671d37440dc0ff3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/229b55b3eae4729a8e2a321441ba40fcb3720b86", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/92b019f6c8d79aa26349d0db7671d37440dc0ff3",
"reference": "229b55b3eae4729a8e2a321441ba40fcb3720b86", "reference": "92b019f6c8d79aa26349d0db7671d37440dc0ff3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -15207,7 +15207,7 @@
"doctrine/lexer": "^2 || ^3", "doctrine/lexer": "^2 || ^3",
"ext-json": "*", "ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": "^8.0.1", "php": "^7.4 || ^8.0",
"sebastian/diff": "^4.0 || ^5.0", "sebastian/diff": "^4.0 || ^5.0",
"symfony/console": "^5.4 || ^6.0", "symfony/console": "^5.4 || ^6.0",
"symfony/event-dispatcher": "^5.4 || ^6.0", "symfony/event-dispatcher": "^5.4 || ^6.0",
@ -15221,6 +15221,7 @@
"symfony/stopwatch": "^5.4 || ^6.0" "symfony/stopwatch": "^5.4 || ^6.0"
}, },
"require-dev": { "require-dev": {
"facile-it/paraunit": "^1.3 || ^2.0",
"justinrainbow/json-schema": "^5.2", "justinrainbow/json-schema": "^5.2",
"keradus/cli-executor": "^2.0", "keradus/cli-executor": "^2.0",
"mikey179/vfsstream": "^1.6.11", "mikey179/vfsstream": "^1.6.11",
@ -15272,7 +15273,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.21.1" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.22.0"
}, },
"funding": [ "funding": [
{ {
@ -15280,7 +15281,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-07-05T21:50:25+00:00" "time": "2023-07-16T23:08:06+00:00"
}, },
{ {
"name": "hamcrest/hamcrest-php", "name": "hamcrest/hamcrest-php",
@ -15460,37 +15461,33 @@
}, },
{ {
"name": "mockery/mockery", "name": "mockery/mockery",
"version": "1.6.2", "version": "1.6.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/mockery/mockery.git", "url": "https://github.com/mockery/mockery.git",
"reference": "13a7fa2642c76c58fa2806ef7f565344c817a191" "reference": "d1413755e26fe56a63455f7753221c86cbb88f66"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/mockery/mockery/zipball/13a7fa2642c76c58fa2806ef7f565344c817a191", "url": "https://api.github.com/repos/mockery/mockery/zipball/d1413755e26fe56a63455f7753221c86cbb88f66",
"reference": "13a7fa2642c76c58fa2806ef7f565344c817a191", "reference": "d1413755e26fe56a63455f7753221c86cbb88f66",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"hamcrest/hamcrest-php": "^2.0.1", "hamcrest/hamcrest-php": "^2.0.1",
"lib-pcre": ">=7.0", "lib-pcre": ">=7.0",
"php": "^7.4 || ^8.0" "php": ">=7.4,<8.3"
}, },
"conflict": { "conflict": {
"phpunit/phpunit": "<8.0" "phpunit/phpunit": "<8.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^8.5 || ^9.3", "phpunit/phpunit": "^8.5 || ^9.3",
"psalm/plugin-phpunit": "^0.18", "psalm/plugin-phpunit": "^0.18.4",
"vimeo/psalm": "^5.9" "symplify/easy-coding-standard": "^11.5.0",
"vimeo/psalm": "^5.13.1"
}, },
"type": "library", "type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.6.x-dev"
}
},
"autoload": { "autoload": {
"files": [ "files": [
"library/helpers.php", "library/helpers.php",
@ -15508,12 +15505,20 @@
{ {
"name": "Pádraic Brady", "name": "Pádraic Brady",
"email": "padraic.brady@gmail.com", "email": "padraic.brady@gmail.com",
"homepage": "http://blog.astrumfutura.com" "homepage": "https://github.com/padraic",
"role": "Author"
}, },
{ {
"name": "Dave Marshall", "name": "Dave Marshall",
"email": "dave.marshall@atstsolutions.co.uk", "email": "dave.marshall@atstsolutions.co.uk",
"homepage": "http://davedevelopment.co.uk" "homepage": "https://davedevelopment.co.uk",
"role": "Developer"
},
{
"name": "Nathanael Esayeas",
"email": "nathanael.esayeas@protonmail.com",
"homepage": "https://github.com/ghostwriter",
"role": "Lead Developer"
} }
], ],
"description": "Mockery is a simple yet flexible PHP mock object framework", "description": "Mockery is a simple yet flexible PHP mock object framework",
@ -15531,10 +15536,13 @@
"testing" "testing"
], ],
"support": { "support": {
"docs": "https://docs.mockery.io/",
"issues": "https://github.com/mockery/mockery/issues", "issues": "https://github.com/mockery/mockery/issues",
"source": "https://github.com/mockery/mockery/tree/1.6.2" "rss": "https://github.com/mockery/mockery/releases.atom",
"security": "https://github.com/mockery/mockery/security/advisories",
"source": "https://github.com/mockery/mockery"
}, },
"time": "2023-06-07T09:07:52+00:00" "time": "2023-07-19T15:51:02+00:00"
}, },
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
@ -16140,16 +16148,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.25", "version": "1.10.26",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "578f4e70d117f9a90699324c555922800ac38d8c" "reference": "5d660cbb7e1b89253a47147ae44044f49832351f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/578f4e70d117f9a90699324c555922800ac38d8c", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5d660cbb7e1b89253a47147ae44044f49832351f",
"reference": "578f4e70d117f9a90699324c555922800ac38d8c", "reference": "5d660cbb7e1b89253a47147ae44044f49832351f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -16198,7 +16206,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-06T12:11:37+00:00" "time": "2023-07-19T12:44:37+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",

View File

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

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('tasks', function (Blueprint $table) {
$table->date('calculated_start_date')->nullable();
});
Schema::table('webhooks', function (Blueprint $table){
$table->text('target_url')->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
};

View File

@ -0,0 +1,48 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$ir = \App\Models\Currency::where('code', 'IDR')->first();
if($ir){
$ir->thousand_separator = '.';
$ir->decimal_separator = ',';
$ir->save();
}
$ld = \App\Models\Currency::find(115);
if(!$ld) {
$ld = new \App\Models\Currency();
$ld->id = 115;
$ld->code = 'LYD';
$ld->name = 'Libyan Dinar';
$ld->symbol = 'LD';
$ld->thousand_separator = ',';
$ld->decimal_separator = '.';
$ld->precision = 3;
$ld->save();
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
};

View File

@ -49,7 +49,7 @@ class CurrenciesSeeder extends Seeder
['id' => 24, 'name' => 'Bangladeshi Taka', 'code' => 'BDT', 'symbol' => 'Tk', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 24, 'name' => 'Bangladeshi Taka', 'code' => 'BDT', 'symbol' => 'Tk', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 25, 'name' => 'United Arab Emirates Dirham', 'code' => 'AED', 'symbol' => 'DH ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 25, 'name' => 'United Arab Emirates Dirham', 'code' => 'AED', 'symbol' => 'DH ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 26, 'name' => 'Hong Kong Dollar', 'code' => 'HKD', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 26, 'name' => 'Hong Kong Dollar', 'code' => 'HKD', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 27, 'name' => 'Indonesian Rupiah', 'code' => 'IDR', 'symbol' => 'Rp', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 27, 'name' => 'Indonesian Rupiah', 'code' => 'IDR', 'symbol' => 'Rp', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['id' => 28, 'name' => 'Mexican Peso', 'code' => 'MXN', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 28, 'name' => 'Mexican Peso', 'code' => 'MXN', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 29, 'name' => 'Egyptian Pound', 'code' => 'EGP', 'symbol' => 'E£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 29, 'name' => 'Egyptian Pound', 'code' => 'EGP', 'symbol' => 'E£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 30, 'name' => 'Colombian Peso', 'code' => 'COP', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','], ['id' => 30, 'name' => 'Colombian Peso', 'code' => 'COP', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
@ -136,6 +136,8 @@ class CurrenciesSeeder extends Seeder
['id' => 111, 'name' => 'Cuban Peso', 'code' => 'CUP', 'symbol' => '₱', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 111, 'name' => 'Cuban Peso', 'code' => 'CUP', 'symbol' => '₱', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 112, 'name' => 'Cayman Island Dollar', 'code' => 'KYD', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 112, 'name' => 'Cayman Island Dollar', 'code' => 'KYD', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 113, 'name' => 'Swazi lilangeni', 'code' => 'SZL', 'symbol' => 'E', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['id' => 113, 'name' => 'Swazi lilangeni', 'code' => 'SZL', 'symbol' => 'E', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 114, 'name' => 'BZ Dollar', 'code' => 'BZD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['id' => 115, 'name' => 'Libyan Dinar', 'code' => 'LYD', 'symbol' => 'LD', 'precision' => '3', 'thousand_separator' => ',', 'decimal_separator' => '.'],
]; ];
foreach ($currencies as $currency) { foreach ($currencies as $currency) {

View File

@ -4,9 +4,9 @@ includes:
parameters: parameters:
treatPhpDocTypesAsCertain: false treatPhpDocTypesAsCertain: false
parallel: parallel:
jobSize: 5 jobSize: 10
maximumNumberOfProcesses: 16 maximumNumberOfProcesses: 1
processTimeout: 600.0 processTimeout: 60.0
ignoreErrors: ignoreErrors:
- '#Call to an undefined method .*badMethod\(\)#' - '#Call to an undefined method .*badMethod\(\)#'
- '#Call to an undefined method Illuminate\Database\Eloquent\Builder::exclude#' - '#Call to an undefined method Illuminate\Database\Eloquent\Builder::exclude#'

View File

@ -3,10 +3,10 @@ const MANIFEST = 'flutter-app-manifest';
const TEMP = 'flutter-temp-cache'; const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache'; const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = { const RESOURCES = {
"/": "0aa10ee6dcb142946702cadae9812704", "/": "dad42af82faab711765c59e9a7596b11",
"flutter.js": "a85fcf6324d3c4d3ae3be1ae4931e9c5", "flutter.js": "a85fcf6324d3c4d3ae3be1ae4931e9c5",
"favicon.png": "dca91c54388f52eded692718d5a98b8b", "favicon.png": "dca91c54388f52eded692718d5a98b8b",
"main.dart.js": "23a2e1cbb7cb043fd5ef1e51de367bb6", "main.dart.js": "b11ed73562dd3c3db2c346bc14702036",
"version.json": "bf49df736fed3f74ade0dbaebf08de11", "version.json": "bf49df736fed3f74ade0dbaebf08de11",
"canvaskit/profiling/canvaskit.js": "c21852696bc1cc82e8894d851c01921a", "canvaskit/profiling/canvaskit.js": "c21852696bc1cc82e8894d851c01921a",
"canvaskit/profiling/canvaskit.wasm": "371bc4e204443b0d5e774d64a046eb99", "canvaskit/profiling/canvaskit.wasm": "371bc4e204443b0d5e774d64a046eb99",

353472
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More