mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #8653 from turbo124/v5-develop
Adjustments for restoring a deleted invoice with a deleted payment
This commit is contained in:
commit
d08a8d74c4
@ -24,8 +24,7 @@ use App\Transformers\ActivityTransformer;
|
||||
|
||||
class ActivityExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
|
||||
private $entity_transformer;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
@ -13,14 +13,14 @@ namespace App\Export\CSV;
|
||||
|
||||
use App\Utils\Number;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use League\Fractal\Manager;
|
||||
use Illuminate\Support\Carbon;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Transformers\ClientTransformer;
|
||||
use App\Transformers\TaskTransformer;
|
||||
use App\Transformers\PaymentTransformer;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use League\Fractal\Serializer\ArraySerializer;
|
||||
@ -29,6 +29,8 @@ class BaseExport
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public Company $company;
|
||||
|
||||
public array $input;
|
||||
|
||||
public string $date_key = '';
|
||||
@ -136,6 +138,35 @@ class BaseExport
|
||||
"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 = [
|
||||
'amount' => 'purchase_order.amount',
|
||||
'balance' => 'purchase_order.balance',
|
||||
@ -193,13 +224,17 @@ class BaseExport
|
||||
];
|
||||
|
||||
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",
|
||||
"balance" => "quote.balance",
|
||||
"paid_to_date" => "quote.paid_to_date",
|
||||
"po_number" => "quote.po_number",
|
||||
"date" => "quote.date",
|
||||
"due_date" => "quote.due_date",
|
||||
"valid_until" => "quote.due_date",
|
||||
"terms" => "quote.terms",
|
||||
"footer" => "quote.footer",
|
||||
"status" => "quote.status",
|
||||
@ -314,8 +349,6 @@ class BaseExport
|
||||
'custom_value4' => 'task.custom_value4',
|
||||
'status' => 'task.status_id',
|
||||
'project' => 'task.project_id',
|
||||
'invoice' => 'task.invoice_id',
|
||||
'client' => 'task.client_id',
|
||||
];
|
||||
|
||||
protected function filterByClients($query)
|
||||
@ -347,8 +380,11 @@ class BaseExport
|
||||
'vendor' => $value = $this->resolveVendorKey($parts[1], $entity, $transformer),
|
||||
'vendor_contact' => $value = $this->resolveVendorContactKey($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),
|
||||
'payment' => $value = $this->resolvePaymentKey($parts[1], $entity, $transformer),
|
||||
'task' => $value = $this->resolveTaskKey($parts[1], $entity, $transformer),
|
||||
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)
|
||||
{
|
||||
|
||||
@ -511,6 +563,20 @@ class BaseExport
|
||||
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)
|
||||
{
|
||||
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')
|
||||
return $entity->stringStatus($entity->status_id);
|
||||
@ -707,8 +789,27 @@ class BaseExport
|
||||
$this->end_date = now()->startOfDay()->format('Y-m-d');
|
||||
return $query->whereBetween($this->date_key, [now()->subDays(365), now()])->orderBy($this->date_key, 'ASC');
|
||||
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');
|
||||
case 'custom':
|
||||
$this->start_date = $custom_start_date->format('Y-m-d');
|
||||
@ -743,6 +844,11 @@ class BaseExport
|
||||
$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) {
|
||||
$prefix = ctrans('texts.payment')." ";
|
||||
$key = array_search($value, $this->payment_report_keys);
|
||||
@ -790,6 +896,7 @@ class BaseExport
|
||||
|
||||
$key = str_replace('item.', '', $key);
|
||||
$key = str_replace('recurring_invoice.', '', $key);
|
||||
$key = str_replace('purchase_order.', '', $key);
|
||||
$key = str_replace('invoice.', '', $key);
|
||||
$key = str_replace('quote.', '', $key);
|
||||
$key = str_replace('credit.', '', $key);
|
||||
@ -800,9 +907,18 @@ class BaseExport
|
||||
$key = str_replace('payment.', '', $key);
|
||||
$key = str_replace('expense.', '', $key);
|
||||
|
||||
$header[] = "{$prefix}" . ctrans("texts.{$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}");
|
||||
}
|
||||
}
|
||||
// nlog($header);
|
||||
|
||||
// nlog($header);
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
@ -22,8 +22,6 @@ use League\Csv\Writer;
|
||||
|
||||
class ClientExport extends BaseExport
|
||||
{
|
||||
private $company;
|
||||
|
||||
private $client_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}") : '';
|
||||
}
|
||||
|
||||
if (in_array('client.currency', $this->input['report_keys'])) {
|
||||
$entity['currency'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
|
||||
if (in_array('client.currency_id', $this->input['report_keys'])) {
|
||||
$entity['client.currency_id'] = $client->currency() ? $client->currency()->code : $client->company->currency()->code;
|
||||
}
|
||||
|
||||
if (in_array('client.industry_id', $this->input['report_keys'])) {
|
||||
|
@ -23,7 +23,6 @@ use League\Csv\Writer;
|
||||
|
||||
class ContactExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private ClientTransformer $client_transformer;
|
||||
|
||||
|
@ -21,7 +21,6 @@ use League\Csv\Writer;
|
||||
|
||||
class CreditExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private CreditTransformer $credit_transformer;
|
||||
|
||||
|
@ -21,7 +21,6 @@ use League\Csv\Writer;
|
||||
|
||||
class DocumentExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $entity_transformer;
|
||||
|
||||
|
@ -21,7 +21,6 @@ use League\Csv\Writer;
|
||||
|
||||
class ExpenseExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $expense_transformer;
|
||||
|
||||
|
@ -23,8 +23,6 @@ use App\Transformers\InvoiceTransformer;
|
||||
|
||||
class InvoiceExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $invoice_transformer;
|
||||
|
||||
public string $date_key = 'date';
|
||||
|
@ -22,7 +22,6 @@ use League\Csv\Writer;
|
||||
|
||||
class InvoiceItemExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $invoice_transformer;
|
||||
|
||||
|
@ -21,8 +21,6 @@ use League\Csv\Writer;
|
||||
|
||||
class PaymentExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $entity_transformer;
|
||||
|
||||
public string $date_key = 'date';
|
||||
|
@ -22,8 +22,6 @@ use League\Csv\Writer;
|
||||
|
||||
class ProductExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $entity_transformer;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
@ -23,8 +23,6 @@ use League\Csv\Writer;
|
||||
|
||||
class ProductSalesExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
public string $date_key = 'created_at';
|
||||
|
||||
protected Collection $products;
|
||||
|
@ -22,7 +22,6 @@ use League\Csv\Writer;
|
||||
|
||||
class PurchaseOrderExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $purchase_order_transformer;
|
||||
|
||||
@ -31,39 +30,39 @@ class PurchaseOrderExport extends BaseExport
|
||||
public Writer $csv;
|
||||
|
||||
public array $entity_keys = [
|
||||
'amount' => 'amount',
|
||||
'balance' => 'balance',
|
||||
'vendor' => 'vendor_id',
|
||||
'custom_surcharge1' => 'custom_surcharge1',
|
||||
'custom_surcharge2' => 'custom_surcharge2',
|
||||
'custom_surcharge3' => 'custom_surcharge3',
|
||||
'custom_surcharge4' => 'custom_surcharge4',
|
||||
'custom_value1' => 'custom_value1',
|
||||
'custom_value2' => 'custom_value2',
|
||||
'custom_value3' => 'custom_value3',
|
||||
'custom_value4' => 'custom_value4',
|
||||
'date' => 'date',
|
||||
'discount' => 'discount',
|
||||
'due_date' => 'due_date',
|
||||
'exchange_rate' => 'exchange_rate',
|
||||
'footer' => 'footer',
|
||||
'number' => 'number',
|
||||
'paid_to_date' => 'paid_to_date',
|
||||
'partial' => 'partial',
|
||||
'partial_due_date' => 'partial_due_date',
|
||||
'po_number' => 'po_number',
|
||||
'private_notes' => 'private_notes',
|
||||
'public_notes' => 'public_notes',
|
||||
'status' => 'status_id',
|
||||
'tax_name1' => 'tax_name1',
|
||||
'tax_name2' => 'tax_name2',
|
||||
'tax_name3' => 'tax_name3',
|
||||
'tax_rate1' => 'tax_rate1',
|
||||
'tax_rate2' => 'tax_rate2',
|
||||
'tax_rate3' => 'tax_rate3',
|
||||
'terms' => 'terms',
|
||||
'total_taxes' => 'total_taxes',
|
||||
'currency_id' => 'currency_id',
|
||||
'amount' => 'purchase_order.amount',
|
||||
'balance' => 'purchase_order.balance',
|
||||
'vendor' => 'purchase_order.vendor_id',
|
||||
// 'custom_surcharge1' => 'purchase_order.custom_surcharge1',
|
||||
// 'custom_surcharge2' => 'purchase_order.custom_surcharge2',
|
||||
// 'custom_surcharge3' => 'purchase_order.custom_surcharge3',
|
||||
// 'custom_surcharge4' => 'purchase_order.custom_surcharge4',
|
||||
'custom_value1' => 'purchase_order.custom_value1',
|
||||
'custom_value2' => 'purchase_order.custom_value2',
|
||||
'custom_value3' => 'purchase_order.custom_value3',
|
||||
'custom_value4' => 'purchase_order.custom_value4',
|
||||
'date' => 'purchase_order.date',
|
||||
'discount' => 'purchase_order.discount',
|
||||
'due_date' => 'purchase_order.due_date',
|
||||
'exchange_rate' => 'purchase_order.exchange_rate',
|
||||
'footer' => 'purchase_order.footer',
|
||||
'number' => 'purchase_order.number',
|
||||
'paid_to_date' => 'purchase_order.paid_to_date',
|
||||
'partial' => 'purchase_order.partial',
|
||||
'partial_due_date' => 'purchase_order.partial_due_date',
|
||||
'po_number' => 'purchase_order.po_number',
|
||||
'private_notes' => 'purchase_order.private_notes',
|
||||
'public_notes' => 'purchase_order.public_notes',
|
||||
'status' => 'purchase_order.status_id',
|
||||
'tax_name1' => 'purchase_order.tax_name1',
|
||||
'tax_name2' => 'purchase_order.tax_name2',
|
||||
'tax_name3' => 'purchase_order.tax_name3',
|
||||
'tax_rate1' => 'purchase_order.tax_rate1',
|
||||
'tax_rate2' => 'purchase_order.tax_rate2',
|
||||
'tax_rate3' => 'purchase_order.tax_rate3',
|
||||
'terms' => 'purchase_order.terms',
|
||||
'total_taxes' => 'purchase_order.total_taxes',
|
||||
'currency_id' => 'purchase_order.currency_id',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
@ -130,7 +129,7 @@ class PurchaseOrderExport extends BaseExport
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
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) {
|
||||
|
@ -21,7 +21,6 @@ use League\Csv\Writer;
|
||||
|
||||
class PurchaseOrderItemExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $purchase_order_transformer;
|
||||
|
||||
@ -37,10 +36,10 @@ class PurchaseOrderItemExport extends BaseExport
|
||||
'vendor' => 'vendor_id',
|
||||
'vendor_number' => 'vendor.number',
|
||||
'vendor_id_number' => 'vendor.id_number',
|
||||
'custom_surcharge1' => 'custom_surcharge1',
|
||||
'custom_surcharge2' => 'custom_surcharge2',
|
||||
'custom_surcharge3' => 'custom_surcharge3',
|
||||
'custom_surcharge4' => 'custom_surcharge4',
|
||||
// 'custom_surcharge1' => 'custom_surcharge1',
|
||||
// 'custom_surcharge2' => 'custom_surcharge2',
|
||||
// 'custom_surcharge3' => 'custom_surcharge3',
|
||||
// 'custom_surcharge4' => 'custom_surcharge4',
|
||||
// 'custom_value1' => 'custom_value1',
|
||||
// 'custom_value2' => 'custom_value2',
|
||||
// 'custom_value3' => 'custom_value3',
|
||||
@ -82,10 +81,10 @@ class PurchaseOrderItemExport extends BaseExport
|
||||
'tax_name3' => 'item.tax_name3',
|
||||
'line_total' => 'item.line_total',
|
||||
'gross_line_total' => 'item.gross_line_total',
|
||||
// 'invoice1' => 'item.custom_value1',
|
||||
// 'invoice2' => 'item.custom_value2',
|
||||
// 'invoice3' => 'item.custom_value3',
|
||||
// 'invoice4' => 'item.custom_value4',
|
||||
'purchase_order1' => 'item.custom_value1',
|
||||
'purchase_order2' => 'item.custom_value2',
|
||||
'purchase_order3' => 'item.custom_value3',
|
||||
'purchase_order4' => 'item.custom_value4',
|
||||
'tax_category' => 'item.tax_id',
|
||||
'type' => 'item.type_id',
|
||||
];
|
||||
@ -139,7 +138,7 @@ class PurchaseOrderItemExport extends BaseExport
|
||||
|
||||
private function iterateItems(PurchaseOrder $purchase_order)
|
||||
{
|
||||
$transformed_invoice = $this->buildRow($purchase_order);
|
||||
$transformed_purchase_order = $this->buildRow($purchase_order);
|
||||
|
||||
$transformed_items = [];
|
||||
|
||||
@ -154,7 +153,7 @@ class PurchaseOrderItemExport extends BaseExport
|
||||
|
||||
$keyval = $key;
|
||||
|
||||
$keyval = str_replace("custom_value", "invoice", $key);
|
||||
$keyval = str_replace("custom_value", "purchase_order", $key);
|
||||
|
||||
if($key == 'type_id') {
|
||||
$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);
|
||||
|
||||
$this->csv->insertOne($entity);
|
||||
@ -193,7 +192,7 @@ class PurchaseOrderItemExport extends BaseExport
|
||||
|
||||
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 = [];
|
||||
|
||||
@ -201,17 +200,17 @@ class PurchaseOrderItemExport extends BaseExport
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
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) {
|
||||
$keyval = $key;
|
||||
}
|
||||
|
||||
if (array_key_exists($key, $transformed_invoice)) {
|
||||
$entity[$keyval] = $transformed_invoice[$key];
|
||||
} elseif (array_key_exists($keyval, $transformed_invoice)) {
|
||||
$entity[$keyval] = $transformed_invoice[$keyval];
|
||||
if (array_key_exists($key, $transformed_purchase_order)) {
|
||||
$entity[$keyval] = $transformed_purchase_order[$key];
|
||||
} elseif (array_key_exists($keyval, $transformed_purchase_order)) {
|
||||
$entity[$keyval] = $transformed_purchase_order[$keyval];
|
||||
} else {
|
||||
$entity[$keyval] = $this->resolveKey($keyval, $purchase_order, $this->purchase_order_transformer);
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ use League\Csv\Writer;
|
||||
|
||||
class QuoteExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $quote_transformer;
|
||||
|
||||
@ -43,7 +42,7 @@ class QuoteExport extends BaseExport
|
||||
'custom_value4' => 'custom_value4',
|
||||
'date' => 'date',
|
||||
'discount' => 'discount',
|
||||
'due_date' => 'due_date',
|
||||
'valid_until' => 'due_date',
|
||||
'exchange_rate' => 'exchange_rate',
|
||||
'footer' => 'footer',
|
||||
'number' => 'number',
|
||||
@ -115,17 +114,28 @@ class QuoteExport extends BaseExport
|
||||
|
||||
private function buildRow(Quote $quote) :array
|
||||
{
|
||||
$transformed_quote = $this->quote_transformer->transform($quote);
|
||||
$transformed_entity = $this->quote_transformer->transform($quote);
|
||||
|
||||
$entity = [];
|
||||
|
||||
foreach (array_values($this->input['report_keys']) as $key) {
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if (array_key_exists($key, $transformed_quote)) {
|
||||
$entity[$keyval] = $transformed_quote[$key];
|
||||
} else {
|
||||
$entity[$keyval] = '';
|
||||
if(!$keyval) {
|
||||
$keyval = array_search(str_replace("invoice.", "", $key), $this->entity_keys) ?? $key;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,6 @@ use League\Csv\Writer;
|
||||
|
||||
class QuoteItemExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $quote_transformer;
|
||||
|
||||
@ -63,10 +62,11 @@ class QuoteItemExport extends BaseExport
|
||||
'terms' => 'terms',
|
||||
'total_taxes' => 'total_taxes',
|
||||
'currency' => 'currency_id',
|
||||
'qty' => 'item.quantity',
|
||||
'unit_cost' => 'item.cost',
|
||||
'quantity' => 'item.quantity',
|
||||
'cost' => 'item.cost',
|
||||
'product_key' => 'item.product_key',
|
||||
'cost' => 'item.product_cost',
|
||||
'buy_price' => 'item.product_cost',
|
||||
'cost' => 'item.cost',
|
||||
'notes' => 'item.notes',
|
||||
'discount' => 'item.discount',
|
||||
'is_amount_discount' => 'item.is_amount_discount',
|
||||
@ -77,11 +77,13 @@ class QuoteItemExport extends BaseExport
|
||||
'tax_name2' => 'item.tax_name2',
|
||||
'tax_name3' => 'item.tax_name3',
|
||||
'line_total' => 'item.line_total',
|
||||
// 'gross_line_total' => 'item.gross_line_total',
|
||||
'custom_value1' => 'item.custom_value1',
|
||||
'custom_value2' => 'item.custom_value2',
|
||||
'custom_value3' => 'item.custom_value3',
|
||||
'custom_value4' => 'item.custom_value4',
|
||||
'gross_line_total' => 'item.gross_line_total',
|
||||
'quote1' => 'item.custom_value1',
|
||||
'quote2' => 'item.custom_value2',
|
||||
'quote3' => 'item.custom_value3',
|
||||
'quote4' => 'item.custom_value4',
|
||||
'tax_category' => 'item.tax_id',
|
||||
'type' => 'item.type_id',
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
@ -135,25 +137,44 @@ class QuoteItemExport extends BaseExport
|
||||
|
||||
$transformed_items = [];
|
||||
|
||||
foreach ($quote->line_items as $item) {
|
||||
$item_array = [];
|
||||
$transformed_items = [];
|
||||
|
||||
foreach (array_values($this->input['report_keys']) as $key) {
|
||||
if (str_contains($key, 'item.')) {
|
||||
$key = str_replace('item.', '', $key);
|
||||
$item_array[$key] = $item->{$key};
|
||||
foreach ($quote->line_items as $item) {
|
||||
$item_array = [];
|
||||
|
||||
foreach (array_values($this->input['report_keys']) as $key) { //items iterator produces item array
|
||||
|
||||
if (str_contains($key, "item.")) {
|
||||
|
||||
$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 = [];
|
||||
|
||||
foreach (array_values($this->input['report_keys']) as $key) {
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
foreach (array_values($this->input['report_keys']) as $key) { //create an array of report keys only
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if (array_key_exists($key, $transformed_items)) {
|
||||
$entity[$keyval] = $transformed_items[$key];
|
||||
} else {
|
||||
$entity[$keyval] = '';
|
||||
$entity[$keyval] = "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,16 +194,26 @@ class QuoteItemExport extends BaseExport
|
||||
foreach (array_values($this->input['report_keys']) as $key) {
|
||||
$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)) {
|
||||
$entity[$keyval] = $transformed_quote[$key];
|
||||
} else {
|
||||
$entity[$keyval] = '';
|
||||
} elseif (array_key_exists($keyval, $transformed_quote)) {
|
||||
$entity[$keyval] = $transformed_quote[$keyval];
|
||||
}
|
||||
else {
|
||||
$entity[$keyval] = $this->resolveKey($keyval, $quote, $this->quote_transformer);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($quote, $entity);
|
||||
}
|
||||
|
||||
private function decorateAdvancedFields(Quote $quote, array $entity) :array
|
||||
{
|
||||
if (in_array('currency_id', $this->input['report_keys'])) {
|
||||
|
@ -21,7 +21,6 @@ use League\Csv\Writer;
|
||||
|
||||
class RecurringInvoiceExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $invoice_transformer;
|
||||
|
||||
@ -33,10 +32,10 @@ class RecurringInvoiceExport extends BaseExport
|
||||
'amount' => 'amount',
|
||||
'balance' => 'balance',
|
||||
'client' => 'client_id',
|
||||
'custom_surcharge1' => 'custom_surcharge1',
|
||||
'custom_surcharge2' => 'custom_surcharge2',
|
||||
'custom_surcharge3' => 'custom_surcharge3',
|
||||
'custom_surcharge4' => 'custom_surcharge4',
|
||||
// 'custom_surcharge1' => 'custom_surcharge1',
|
||||
// 'custom_surcharge2' => 'custom_surcharge2',
|
||||
// 'custom_surcharge3' => 'custom_surcharge3',
|
||||
// 'custom_surcharge4' => 'custom_surcharge4',
|
||||
'custom_value1' => 'custom_value1',
|
||||
'custom_value2' => 'custom_value2',
|
||||
'custom_value3' => 'custom_value3',
|
||||
@ -66,7 +65,8 @@ class RecurringInvoiceExport extends BaseExport
|
||||
'currency' => 'currency_id',
|
||||
'vendor' => 'vendor_id',
|
||||
'project' => 'project_id',
|
||||
'frequency' => 'frequency_id'
|
||||
'frequency_id' => 'frequency_id',
|
||||
'next_send_date' => 'next_send_date'
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
@ -127,11 +127,22 @@ class RecurringInvoiceExport extends BaseExport
|
||||
foreach (array_values($this->input['report_keys']) as $key) {
|
||||
$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)) {
|
||||
$entity[$keyval] = $transformed_invoice[$key];
|
||||
} elseif (array_key_exists($keyval, $transformed_invoice)) {
|
||||
$entity[$keyval] = $transformed_invoice[$keyval];
|
||||
} else {
|
||||
$entity[$keyval] = '';
|
||||
$entity[$keyval] = $this->resolveKey($keyval, $invoice, $this->invoice_transformer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->decorateAdvancedFields($invoice, $entity);
|
||||
@ -163,7 +174,9 @@ class RecurringInvoiceExport extends BaseExport
|
||||
$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;
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ use League\Csv\Writer;
|
||||
|
||||
class TaskExport extends BaseExport
|
||||
{
|
||||
private Company $company;
|
||||
|
||||
private $entity_transformer;
|
||||
|
||||
@ -47,9 +46,7 @@ class TaskExport extends BaseExport
|
||||
'custom_value4' => 'custom_value4',
|
||||
'status' => 'status_id',
|
||||
'project' => 'project_id',
|
||||
'invoice' => 'invoice_id',
|
||||
'client' => 'client_id',
|
||||
];
|
||||
];
|
||||
|
||||
private array $decorate_keys = [
|
||||
'status',
|
||||
@ -110,38 +107,39 @@ class TaskExport extends BaseExport
|
||||
$entity = [];
|
||||
$transformed_entity = $this->entity_transformer->transform($task);
|
||||
|
||||
foreach (array_values($this->input['report_keys']) as $key) {
|
||||
$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)) {
|
||||
$entity[$keyval] = $transformed_entity[$key];
|
||||
} elseif (array_key_exists($keyval, $transformed_entity)) {
|
||||
$entity[$keyval] = $transformed_entity[$keyval];
|
||||
}
|
||||
else {
|
||||
$entity[$keyval] = $this->resolveKey($keyval, $task, $this->entity_transformer);
|
||||
}
|
||||
}
|
||||
|
||||
$entity['start_date'] = '';
|
||||
$entity['end_date'] = '';
|
||||
$entity['duration'] = '';
|
||||
|
||||
|
||||
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) {
|
||||
$keyval = array_search($key, $this->entity_keys);
|
||||
|
||||
if (array_key_exists($key, $transformed_entity)) {
|
||||
$entity[$keyval] = $transformed_entity[$key];
|
||||
} else {
|
||||
$entity[$keyval] = '';
|
||||
}
|
||||
}
|
||||
|
||||
$entity['start_date'] = '';
|
||||
$entity['end_date'] = '';
|
||||
$entity['duration'] = '';
|
||||
|
||||
$entity = $this->decorateAdvancedFields($task, $entity);
|
||||
|
||||
ksort($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 {
|
||||
$entity[$keyval] = '';
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->iterateLogs($task, $entity);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function iterateLogs(Task $task, array $entity)
|
||||
@ -164,39 +162,26 @@ class TaskExport extends BaseExport
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ksort($entity);
|
||||
|
||||
$this->csv->insertOne($entity);
|
||||
|
||||
|
||||
unset($entity['start_date']);
|
||||
unset($entity['end_date']);
|
||||
unset($entity['duration']);
|
||||
@ -213,14 +198,6 @@ class TaskExport extends BaseExport
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ use League\Csv\Writer;
|
||||
|
||||
class VendorExport extends BaseExport
|
||||
{
|
||||
private $company;
|
||||
|
||||
private $vendor_transformer;
|
||||
|
||||
@ -115,7 +114,7 @@ class VendorExport extends BaseExport
|
||||
|
||||
private function buildRow(Vendor $vendor) :array
|
||||
{
|
||||
$transformed_contact = false;
|
||||
$transformed_contact = [];
|
||||
|
||||
$transformed_vendor = $this->vendor_transformer->transform($vendor);
|
||||
|
||||
|
@ -49,7 +49,7 @@ class CreditFactory
|
||||
$credit->user_id = $user_id;
|
||||
$credit->company_id = $company_id;
|
||||
$credit->recurring_id = null;
|
||||
|
||||
$credit->exchange_rate = 1;
|
||||
return $credit;
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,8 @@ class PurchaseOrderFactory
|
||||
$purchase_order->user_id = $user_id;
|
||||
$purchase_order->company_id = $company_id;
|
||||
$purchase_order->recurring_id = null;
|
||||
|
||||
$purchase_order->exchange_rate = 1;
|
||||
|
||||
return $purchase_order;
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ class QuoteFactory
|
||||
$quote->user_id = $user_id;
|
||||
$quote->company_id = $company_id;
|
||||
$quote->paid_to_date = 0;
|
||||
$quote->exchange_rate = 1;
|
||||
|
||||
return $quote;
|
||||
}
|
||||
|
@ -32,11 +32,12 @@ class ExpenseFilters extends QueryFilters
|
||||
}
|
||||
|
||||
return $this->builder->where(function ($query) use ($filter) {
|
||||
$query->where('public_notes', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value4', 'like', '%'.$filter.'%');
|
||||
$query->where('number', 'like', '%'.$filter.'%')
|
||||
->orWhere('public_notes', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||
->orWhere('custom_value4', 'like', '%'.$filter.'%');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -238,14 +238,20 @@ class InvoiceItemSum
|
||||
{
|
||||
$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_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_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_rate3 = $this->rule->tax_rate3;
|
||||
$this->item->tax_rate3 = round($this->rule->tax_rate3, $precision);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -11,24 +11,23 @@
|
||||
|
||||
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 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
|
||||
{
|
||||
use PdfMaker, PageNumbering;
|
||||
use PdfMaker, PageNumbering, MakesHash;
|
||||
|
||||
protected $entity_type = Activity::class;
|
||||
|
||||
@ -39,50 +38,6 @@ class ActivityController extends BaseController
|
||||
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)
|
||||
{
|
||||
$default_activities = $request->has('rows') ? $request->input('rows') : 75;
|
||||
@ -115,47 +70,36 @@ class ActivityController extends BaseController
|
||||
return $this->listResponse($activities);
|
||||
}
|
||||
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/v1/actvities/download_entity/{activity_id}",
|
||||
* operationId="getActivityHistoricalEntityPdf",
|
||||
* tags={"actvities"},
|
||||
* summary="Gets a PDF for the given activity",
|
||||
* description="Gets a PDF for the given activity",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||
* @OA\Parameter(
|
||||
* name="activity_id",
|
||||
* in="path",
|
||||
* description="The Activity Hashed ID",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="PDF File",
|
||||
* @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\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 entityActivity(ShowActivityRequest $request)
|
||||
{
|
||||
|
||||
$default_activities = request()->has('rows') ? request()->input('rows') : 75;
|
||||
|
||||
$activities = Activity::with('user')
|
||||
->orderBy('created_at', 'DESC')
|
||||
->company()
|
||||
->where("{$request->entity}_id", $request->entity_id)
|
||||
->take($default_activities);
|
||||
|
||||
/** @var \App\Models\User auth()->user() */
|
||||
$user = auth()->user();
|
||||
|
||||
if (!$user->isAdmin()) {
|
||||
$activities->where('user_id', auth()->user()->id);
|
||||
}
|
||||
|
||||
$system = ctrans('texts.system');
|
||||
|
||||
$data = $activities->cursor()->map(function ($activity) use ($system) {
|
||||
|
||||
return $activity->activity_string();
|
||||
|
||||
});
|
||||
|
||||
return response()->json(['data' => $data->toArray()], 200);
|
||||
|
||||
}
|
||||
|
||||
public function downloadHistoricalEntity(DownloadHistoricalEntityRequest $request, Activity $activity)
|
||||
{
|
||||
$backup = $activity->backup;
|
||||
|
@ -86,7 +86,7 @@ class InvoiceController extends Controller
|
||||
|
||||
public function showBlob($hash)
|
||||
{
|
||||
$data = Cache::pull($hash);
|
||||
$data = Cache::get($hash);
|
||||
|
||||
match($data['entity_type']){
|
||||
'invoice' => $invitation = InvoiceInvitation::withTrashed()->find($data['invitation_id']),
|
||||
|
@ -29,8 +29,10 @@ class ProtectedDownloadController extends BaseController
|
||||
throw new SystemError('File no longer available', 404);
|
||||
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), []);
|
||||
|
||||
}
|
||||
|
||||
|
@ -12,10 +12,12 @@
|
||||
namespace App\Http\Requests\Activity;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Activity;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class ShowActivityRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
@ -23,7 +25,25 @@ class ShowActivityRequest extends Request
|
||||
*/
|
||||
public function authorize() : bool
|
||||
{
|
||||
// return auth()->user()->isAdmin();
|
||||
return auth()->user()->can('view', Activity::class);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class ShowChartRequest extends Request
|
||||
$input = $this->all();
|
||||
|
||||
if(isset($input['date_range'])) {
|
||||
$dates = $this->calculateStartAndEndDates($input);
|
||||
$dates = $this->calculateStartAndEndDates($input, auth()->user()->company());
|
||||
$input['start_date'] = $dates[0];
|
||||
$input['end_date'] = $dates[1];
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ class StoreCreditRequest extends Request
|
||||
$rules['tax_name1'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name2'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name3'] = 'bail|sometimes|string|nullable';
|
||||
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
if ($this->invoice_id) {
|
||||
$rules['invoice_id'] = new ValidInvoiceCreditRule();
|
||||
}
|
||||
@ -88,7 +89,11 @@ class StoreCreditRequest extends Request
|
||||
$input = $this->decodePrimaryKeys($input);
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ class UpdateCreditRequest extends Request
|
||||
$rules['tax_name1'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name2'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name3'] = 'bail|sometimes|string|nullable';
|
||||
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
@ -81,6 +82,10 @@ class UpdateCreditRequest extends Request
|
||||
$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;
|
||||
|
||||
$this->replace($input);
|
||||
|
@ -72,7 +72,8 @@ class StoreInvoiceRequest extends Request
|
||||
$rules['tax_name1'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name2'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name3'] = 'bail|sometimes|string|nullable';
|
||||
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,8 @@ class UpdateInvoiceRequest extends Request
|
||||
$rules['tax_name2'] = '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['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
// not needed.
|
||||
// $rules['partial_due_date'] = 'bail|sometimes|required_unless:partial,0,null';
|
||||
|
||||
@ -95,6 +96,10 @@ class UpdateInvoiceRequest extends Request
|
||||
unset($input['documents']);
|
||||
}
|
||||
|
||||
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
|
||||
$input['exchange_rate'] = 1;
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,8 @@ class StorePurchaseOrderRequest extends Request
|
||||
}
|
||||
|
||||
$rules['status_id'] = 'nullable|integer|in:1,2,3,4,5';
|
||||
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
@ -77,6 +78,10 @@ class StorePurchaseOrderRequest extends Request
|
||||
$input['amount'] = 0;
|
||||
$input['balance'] = 0;
|
||||
|
||||
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
|
||||
$input['exchange_rate'] = 1;
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ class UpdatePurchaseOrderRequest extends Request
|
||||
}
|
||||
|
||||
$rules['status_id'] = 'sometimes|integer|in:1,2,3,4,5';
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
return $rules;
|
||||
}
|
||||
@ -79,6 +80,10 @@ class UpdatePurchaseOrderRequest extends Request
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ class StoreQuoteRequest extends Request
|
||||
$rules['discount'] = 'sometimes|numeric';
|
||||
|
||||
$rules['is_amount_discount'] = ['boolean'];
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
// $rules['number'] = new UniqueQuoteNumberRule($this->all());
|
||||
$rules['line_items'] = 'array';
|
||||
@ -72,6 +73,10 @@ class StoreQuoteRequest extends Request
|
||||
$input['amount'] = 0;
|
||||
$input['balance'] = 0;
|
||||
|
||||
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
|
||||
$input['exchange_rate'] = 1;
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ class UpdateQuoteRequest extends Request
|
||||
$rules['line_items'] = 'array';
|
||||
$rules['discount'] = 'sometimes|numeric';
|
||||
$rules['is_amount_discount'] = ['boolean'];
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
return $rules;
|
||||
}
|
||||
@ -75,6 +76,10 @@ class UpdateQuoteRequest extends Request
|
||||
unset($input['documents']);
|
||||
}
|
||||
|
||||
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
|
||||
$input['exchange_rate'] = 1;
|
||||
}
|
||||
|
||||
$input['id'] = $this->quote->id;
|
||||
|
||||
$this->replace($input);
|
||||
|
@ -67,7 +67,8 @@ class StoreRecurringInvoiceRequest extends Request
|
||||
$rules['tax_name2'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name3'] = 'bail|sometimes|string|nullable';
|
||||
$rules['due_date_days'] = 'bail|sometimes|string';
|
||||
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
@ -143,6 +144,10 @@ class StoreRecurringInvoiceRequest extends Request
|
||||
unset($input['number']);
|
||||
}
|
||||
|
||||
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
|
||||
$input['exchange_rate'] = 1;
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,8 @@ class UpdateRecurringInvoiceRequest extends Request
|
||||
$rules['tax_name1'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name2'] = 'bail|sometimes|string|nullable';
|
||||
$rules['tax_name3'] = 'bail|sometimes|string|nullable';
|
||||
|
||||
$rules['exchange_rate'] = 'bail|sometimes|gt:0';
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
@ -121,6 +122,10 @@ class UpdateRecurringInvoiceRequest extends Request
|
||||
unset($input['documents']);
|
||||
}
|
||||
|
||||
if (array_key_exists('exchange_rate', $input) && is_null($input['exchange_rate'])) {
|
||||
$input['exchange_rate'] = 1;
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
|
||||
|
@ -319,6 +319,21 @@ class BaseTransformer
|
||||
// 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
|
||||
*
|
||||
|
@ -114,7 +114,7 @@ class InvoiceTransformer extends BaseTransformer
|
||||
$invoice_data,
|
||||
'invoice.custom_surcharge4'
|
||||
),
|
||||
'exchange_rate' => $this->getString(
|
||||
'exchange_rate' => $this->getFloatOrOne(
|
||||
$invoice_data,
|
||||
'invoice.exchange_rate'
|
||||
),
|
||||
|
@ -46,7 +46,7 @@ class PaymentTransformer extends BaseTransformer
|
||||
$data,
|
||||
'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'),
|
||||
'custom_value1' => $this->getString($data, 'payment.custom_value1'),
|
||||
'custom_value2' => $this->getString($data, 'payment.custom_value2'),
|
||||
|
@ -114,7 +114,7 @@ class QuoteTransformer extends BaseTransformer
|
||||
$quote_data,
|
||||
'quote.custom_surcharge4'
|
||||
),
|
||||
'exchange_rate' => $this->getString(
|
||||
'exchange_rate' => $this->getFloatOrOne(
|
||||
$quote_data,
|
||||
'quote.exchange_rate'
|
||||
),
|
||||
|
@ -122,7 +122,7 @@ class RecurringInvoiceTransformer extends BaseTransformer
|
||||
$invoice_data,
|
||||
'invoice.custom_surcharge4'
|
||||
),
|
||||
'exchange_rate' => $this->getString(
|
||||
'exchange_rate' => $this->getFloat(
|
||||
$invoice_data,
|
||||
'invoice.exchange_rate'
|
||||
),
|
||||
|
@ -129,12 +129,10 @@ class ReminderJob implements ShouldQueue
|
||||
$invoice->service()->touchReminder($reminder_template)->save();
|
||||
$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);
|
||||
}
|
||||
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
|
||||
$enabled_reminder = 'enable_'.$reminder_template;
|
||||
|
@ -554,7 +554,7 @@ class Account extends BaseModel
|
||||
$nmo->to_user = $this->companies()->first()->owner();
|
||||
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')) {
|
||||
$this->companies()->first()->notification(new EmailQuotaNotification($this))->ninja();
|
||||
|
@ -455,7 +455,7 @@ class Quote extends BaseModel
|
||||
case self::STATUS_DRAFT:
|
||||
return ctrans('texts.draft');
|
||||
case self::STATUS_SENT:
|
||||
return ctrans('texts.pending');
|
||||
return ctrans('texts.sent');
|
||||
case self::STATUS_APPROVED:
|
||||
return ctrans('texts.approved');
|
||||
case self::STATUS_EXPIRED:
|
||||
|
@ -440,6 +440,9 @@ class CheckoutComPaymentDriver extends BaseDriver
|
||||
$request->query('cko-session-id')
|
||||
);
|
||||
|
||||
nlog("checkout3ds");
|
||||
nlog($payment);
|
||||
|
||||
if (isset($payment['approved']) && $payment['approved']) {
|
||||
return $this->processSuccessfulPayment($payment);
|
||||
} else {
|
||||
|
@ -180,6 +180,8 @@ class BaseRepository
|
||||
unset($tmp_data['client_contacts']);
|
||||
}
|
||||
|
||||
nlog($tmp_data);
|
||||
|
||||
$model->fill($tmp_data);
|
||||
|
||||
$model->custom_surcharge_tax1 = $client->company->custom_surcharge_taxes1;
|
||||
|
@ -97,6 +97,10 @@ class InvoiceRepository extends BaseRepository
|
||||
// reversed delete invoice actions
|
||||
$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);
|
||||
|
||||
return $invoice;
|
||||
|
@ -101,9 +101,6 @@ class TaskRepository extends BaseRepository
|
||||
$key_values = array_column($time_log, 0);
|
||||
array_multisort($key_values, SORT_ASC, $time_log);
|
||||
|
||||
// array_multisort($time_log);
|
||||
// ksort($time_log);
|
||||
|
||||
if (isset($data['action'])) {
|
||||
if ($data['action'] == 'start') {
|
||||
$task->is_running = true;
|
||||
@ -121,8 +118,12 @@ class TaskRepository extends BaseRepository
|
||||
$task->is_running = $data['is_running'] ? 1 : 0;
|
||||
}
|
||||
|
||||
$task->calculated_start_date = $this->harvestStartDate($time_log);
|
||||
|
||||
$task->time_log = json_encode($time_log);
|
||||
|
||||
|
||||
|
||||
$task->saveQuietly();
|
||||
|
||||
if (array_key_exists('documents', $data)) {
|
||||
@ -132,6 +133,17 @@ class TaskRepository extends BaseRepository
|
||||
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.
|
||||
*
|
||||
@ -199,8 +211,12 @@ class TaskRepository extends BaseRepository
|
||||
if (strlen($task->time_log) < 5) {
|
||||
$log = [];
|
||||
|
||||
$log = array_merge($log, [[time(), 0]]);
|
||||
$start_time = time();
|
||||
|
||||
$log = array_merge($log, [[$start_time, 0]]);
|
||||
$task->time_log = json_encode($log);
|
||||
$task->calculated_start_date = \Carbon\Carbon::createFromTimestamp($start_time);
|
||||
|
||||
$task->saveQuietly();
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,9 @@ class VendorRepository extends BaseRepository
|
||||
public function save(array $data, Vendor $vendor) : ?Vendor
|
||||
{
|
||||
$vendor->fill($data);
|
||||
|
||||
|
||||
nlog($data);
|
||||
|
||||
$vendor->saveQuietly();
|
||||
|
||||
if ($vendor->number == '' || ! $vendor->number) {
|
||||
|
@ -44,6 +44,7 @@ class HandleRestore extends AbstractService
|
||||
//cannot restore an invoice with a deleted payment
|
||||
foreach ($this->invoice->payments as $payment) {
|
||||
if (($this->invoice->paid_to_date == 0) && $payment->is_deleted) {
|
||||
$this->invoice->delete();
|
||||
return $this->invoice;
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ class TaskTransformer extends EntityTransformer
|
||||
'status',
|
||||
'project',
|
||||
'user',
|
||||
'invoice',
|
||||
];
|
||||
|
||||
public function includeDocuments(Task $task)
|
||||
@ -46,6 +47,17 @@ class TaskTransformer extends EntityTransformer
|
||||
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
|
||||
{
|
||||
$transformer = new UserTransformer($this->serializer);
|
||||
|
@ -583,8 +583,11 @@ class HtmlEngine
|
||||
|
||||
if ($this->settings->signature_on_pdf) {
|
||||
$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 {
|
||||
$data['$contact.signature'] = ['value' => '', 'label' => ''];
|
||||
$data['$contact.signature_date'] = ['value' => '', 'label' => ctrans('texts.date')];
|
||||
}
|
||||
|
||||
$data['$thanks'] = ['value' => '', 'label' => ctrans('texts.thanks')];
|
||||
|
@ -14,6 +14,7 @@ namespace App\Utils\Traits;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Company;
|
||||
use App\DataMapper\Schedule\EmailStatement;
|
||||
|
||||
/**
|
||||
@ -119,8 +120,32 @@ trait MakesDates
|
||||
*
|
||||
* @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']) {
|
||||
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')],
|
||||
@ -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::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::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')],
|
||||
EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->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 => [$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']],
|
||||
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
|
||||
};
|
||||
|
@ -0,0 +1,29 @@
|
||||
<?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();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
}
|
||||
};
|
@ -4,9 +4,9 @@ includes:
|
||||
parameters:
|
||||
treatPhpDocTypesAsCertain: false
|
||||
parallel:
|
||||
jobSize: 5
|
||||
maximumNumberOfProcesses: 16
|
||||
processTimeout: 600.0
|
||||
jobSize: 10
|
||||
maximumNumberOfProcesses: 1
|
||||
processTimeout: 60.0
|
||||
ignoreErrors:
|
||||
- '#Call to an undefined method .*badMethod\(\)#'
|
||||
- '#Call to an undefined method Illuminate\Database\Eloquent\Builder::exclude#'
|
||||
|
@ -143,6 +143,7 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
|
||||
Route::get('health_check', [PingController::class, 'health'])->name('health_check');
|
||||
|
||||
Route::get('activities', [ActivityController::class, 'index']);
|
||||
Route::post('activities/entity', [ActivityController::class, 'entityActivity']);
|
||||
Route::get('activities/download_entity/{activity}', [ActivityController::class, 'downloadHistoricalEntity']);
|
||||
|
||||
Route::post('charts/totals', [ChartController::class, 'totals'])->name('chart.totals');
|
||||
@ -406,6 +407,6 @@ Route::post('api/v1/yodlee/data_updates', [YodleeController::class, 'dataUpdates
|
||||
Route::post('api/v1/yodlee/refresh_updates', [YodleeController::class, 'refreshUpdatesWebhook'])->middleware('throttle:100,1');
|
||||
Route::post('api/v1/yodlee/balance', [YodleeController::class, 'balanceWebhook'])->middleware('throttle:100,1');
|
||||
|
||||
Route::get('api/v1/protected_download/{hash}', [ProtectedDownloadController::class, 'index'])->name('protected_download')->middleware('signed')->middleware('throttle:300,1');
|
||||
Route::get('api/v1/protected_download/{hash}', [ProtectedDownloadController::class, 'index'])->name('protected_download')->middleware('throttle:300,1');
|
||||
|
||||
Route::fallback([BaseController::class, 'notFound'])->middleware('throttle:404');
|
@ -11,10 +11,11 @@
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
use Tests\MockAccountData;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
/**
|
||||
* @test
|
||||
@ -34,6 +35,38 @@ class ActivityApiTest extends TestCase
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
}
|
||||
|
||||
public function testActivityEntity()
|
||||
{
|
||||
|
||||
$invoice = $this->company->invoices()->first();
|
||||
|
||||
$invoice->service()->markSent()->markPaid()->markDeleted()->handleRestore()->save();
|
||||
|
||||
$data = [
|
||||
'entity' => 'invoice',
|
||||
'entity_id' => $invoice->hashed_id
|
||||
];
|
||||
|
||||
$response = false;
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/activities/entity', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
nlog($message);
|
||||
}
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testActivityGet()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,20 +11,21 @@
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use Tests\MockAccountData;
|
||||
use App\Models\ClientContact;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
/**
|
||||
* @test
|
||||
@ -189,4 +190,172 @@ class PaymentV2Test extends TestCase
|
||||
$this->assertEquals(20, $client->fresh()->paid_to_date);
|
||||
|
||||
}
|
||||
|
||||
public function testStorePaymentWithCreditsThenDeletingInvoicesAndThenPayments()
|
||||
{
|
||||
$client = Client::factory()->create(['company_id' =>$this->company->id, 'user_id' => $this->user->id, 'balance' => 100, 'paid_to_date' => 0]);
|
||||
ClientContact::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_primary' => 1,
|
||||
]);
|
||||
|
||||
$line_items = [];
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 100;
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
$invoice = Invoice::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $client->id,
|
||||
'status_id' => Invoice::STATUS_SENT,
|
||||
'uses_inclusive_taxes' => false,
|
||||
'amount' => 100,
|
||||
'balance' => 100,
|
||||
'discount' => 0,
|
||||
'number' => uniqid("st", true),
|
||||
'line_items' => $line_items
|
||||
]);
|
||||
|
||||
$this->assertEquals(100, $client->balance);
|
||||
$this->assertEquals(0, $client->paid_to_date);
|
||||
$this->assertEquals(100, $invoice->amount);
|
||||
$this->assertEquals(100, $invoice->balance);
|
||||
|
||||
$credit = Credit::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $client->id,
|
||||
'status_id' => Invoice::STATUS_SENT,
|
||||
'uses_inclusive_taxes' => false,
|
||||
'amount' => 20,
|
||||
'balance' => 20,
|
||||
'discount' => 0,
|
||||
'number' => uniqid("st", true),
|
||||
'line_items' => []
|
||||
]);
|
||||
|
||||
$this->assertEquals(20, $credit->amount);
|
||||
$this->assertEquals(20, $credit->balance);
|
||||
|
||||
$data = [
|
||||
'client_id' => $client->hashed_id,
|
||||
'invoices' => [
|
||||
[
|
||||
'invoice_id' => $invoice->hashed_id,
|
||||
'amount' => 100,
|
||||
],
|
||||
],
|
||||
'credits' => [
|
||||
[
|
||||
'credit_id' => $credit->hashed_id,
|
||||
'amount' => 20,
|
||||
],
|
||||
],
|
||||
'date' => '2020/12/12',
|
||||
|
||||
];
|
||||
|
||||
$response = null;
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/payments?include=invoices', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
nlog($message);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
$arr = $response->json();
|
||||
$response->assertStatus(200);
|
||||
|
||||
$payment_id = $arr['data']['id'];
|
||||
|
||||
$payment = Payment::find($this->decodePrimaryKey($payment_id));
|
||||
$credit = $credit->fresh();
|
||||
|
||||
$this->assertNotNull($payment);
|
||||
$this->assertNotNull($payment->invoices());
|
||||
$this->assertEquals(1, $payment->invoices()->count());
|
||||
$this->assertEquals(80, $payment->amount);
|
||||
$this->assertEquals(0, $client->fresh()->balance);
|
||||
$this->assertEquals(100, $client->fresh()->paid_to_date);
|
||||
$this->assertEquals(0, $credit->balance);
|
||||
|
||||
$invoice = $invoice->fresh();
|
||||
|
||||
//delete the invoice
|
||||
|
||||
$data = [
|
||||
'action' => 'delete',
|
||||
'ids' => [
|
||||
$invoice->hashed_id,
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/invoices/bulk', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$payment = $payment->fresh();
|
||||
$invoice = $invoice->fresh();
|
||||
|
||||
$this->assertTrue($invoice->is_deleted);
|
||||
$this->assertFalse($payment->is_deleted);
|
||||
|
||||
$data = [
|
||||
'action' => 'delete',
|
||||
'ids' => [
|
||||
$payment->hashed_id,
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/payments/bulk', $data);
|
||||
|
||||
$payment = $payment->fresh();
|
||||
$this->assertTrue($payment->is_deleted);
|
||||
|
||||
$data = [
|
||||
'action' => 'restore',
|
||||
'ids' => [
|
||||
$invoice->hashed_id,
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/invoices/bulk', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$invoice = $invoice->fresh();
|
||||
|
||||
$this->assertTrue($invoice->is_deleted);
|
||||
$this->assertTrue($invoice->trashed());
|
||||
|
||||
$client = $client->fresh();
|
||||
$credit = $credit->fresh();
|
||||
|
||||
$this->assertEquals(0, $client->balance);
|
||||
$this->assertEquals(0, $client->paid_to_date);
|
||||
// $this->assertEquals(20, $client->credit_balance);
|
||||
$this->assertEquals(20, $credit->balance);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -31,6 +31,8 @@ class TaskApiTest extends TestCase
|
||||
use DatabaseTransactions;
|
||||
use MockAccountData;
|
||||
|
||||
private $faker;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
@ -100,6 +102,20 @@ class TaskApiTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testStartDate()
|
||||
{
|
||||
$x = [];
|
||||
|
||||
$this->assertFalse(isset($x[0][0]));
|
||||
|
||||
$x[0][0] = 'a';
|
||||
|
||||
$this->assertTrue(isset($x[0][0]));
|
||||
|
||||
$this->assertNotNull(\Carbon\Carbon::createFromTimestamp($x[0][0]));
|
||||
|
||||
}
|
||||
|
||||
public function testMultiSortArray()
|
||||
{
|
||||
|
||||
|
@ -31,6 +31,150 @@ class DatesTest extends TestCase
|
||||
// $this->makeTestData();
|
||||
}
|
||||
|
||||
public function testLastFinancialYear3()
|
||||
{
|
||||
$this->travelTo(now()->createFromDate(2020, 6, 30));
|
||||
|
||||
//override for financial years
|
||||
$first_month_of_year = 7;
|
||||
$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->assertEquals('2018-07-01', $fin_year_start->format('Y-m-d'));
|
||||
$this->assertEquals('2019-06-30', $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d'));
|
||||
|
||||
$this->travelBack();
|
||||
|
||||
}
|
||||
|
||||
public function testLastFinancialYear2()
|
||||
{
|
||||
$this->travelTo(now()->createFromDate(2020, 7, 1));
|
||||
|
||||
//override for financial years
|
||||
$first_month_of_year = 7;
|
||||
$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->assertEquals('2019-07-01', $fin_year_start->format('Y-m-d'));
|
||||
$this->assertEquals('2020-06-30', $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d'));
|
||||
|
||||
$this->travelBack();
|
||||
|
||||
}
|
||||
|
||||
public function testLastFinancialYear()
|
||||
{
|
||||
$this->travelTo(now()->createFromDate(2020, 12, 1));
|
||||
|
||||
//override for financial years
|
||||
$first_month_of_year = 7;
|
||||
$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->assertEquals('2019-07-01', $fin_year_start->format('Y-m-d'));
|
||||
$this->assertEquals('2020-06-30', $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d'));
|
||||
|
||||
$this->travelBack();
|
||||
|
||||
}
|
||||
|
||||
public function testFinancialYearDates4()
|
||||
{
|
||||
$this->travelTo(now()->createFromDate(2020, 12, 1));
|
||||
|
||||
$first_month_of_year = 7;
|
||||
|
||||
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
|
||||
|
||||
if(now()->lt($fin_year_start))
|
||||
$fin_year_start->subYear();
|
||||
|
||||
$fin_year_end = $fin_year_start->copy()->addYear()->subDay();
|
||||
|
||||
$this->assertEquals('2020-07-01', $fin_year_start->format('Y-m-d'));
|
||||
$this->assertEquals('2021-06-30', $fin_year_end->format('Y-m-d'));
|
||||
|
||||
$this->travelBack();
|
||||
|
||||
}
|
||||
|
||||
public function testFinancialYearDates3()
|
||||
{
|
||||
$this->travelTo(now()->createFromDate(2021, 12, 1));
|
||||
|
||||
$first_month_of_year = 7;
|
||||
|
||||
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
|
||||
|
||||
if(now()->lt($fin_year_start))
|
||||
$fin_year_start->subYear();
|
||||
|
||||
$fin_year_end = $fin_year_start->copy()->addYear()->subDay();
|
||||
|
||||
$this->assertEquals('2021-07-01', $fin_year_start->format('Y-m-d'));
|
||||
$this->assertEquals('2022-06-30', $fin_year_end->format('Y-m-d'));
|
||||
|
||||
$this->travelBack();
|
||||
|
||||
}
|
||||
|
||||
public function testFinancialYearDates2()
|
||||
{
|
||||
$this->travelTo(now()->createFromDate(2021, 8, 1));
|
||||
|
||||
$first_month_of_year = 7;
|
||||
|
||||
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
|
||||
|
||||
if(now()->lt($fin_year_start))
|
||||
$fin_year_start->subYear();
|
||||
|
||||
$fin_year_end = $fin_year_start->copy()->addYear()->subDay();
|
||||
|
||||
$this->assertEquals('2021-07-01', $fin_year_start->format('Y-m-d'));
|
||||
$this->assertEquals('2022-06-30', $fin_year_end->format('Y-m-d'));
|
||||
|
||||
$this->travelBack();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function testFinancialYearDates()
|
||||
{
|
||||
$this->travelTo(now()->createFromDate(2021, 1, 1));
|
||||
|
||||
$first_month_of_year = 7;
|
||||
|
||||
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
|
||||
|
||||
if(now()->lt($fin_year_start))
|
||||
$fin_year_start->subYear();
|
||||
|
||||
$fin_year_end = $fin_year_start->copy()->addYear()->subDay();
|
||||
|
||||
$this->assertEquals('2020-07-01', $fin_year_start->format('Y-m-d'));
|
||||
$this->assertEquals('2021-06-30', $fin_year_end->format('Y-m-d'));
|
||||
|
||||
$this->travelBack();
|
||||
|
||||
}
|
||||
|
||||
public function testDaysDiff()
|
||||
{
|
||||
$string_date = '2021-06-01';
|
||||
|
Loading…
x
Reference in New Issue
Block a user