diff --git a/VERSION.txt b/VERSION.txt index cc5a1231e0..0e6854f58e 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.8.54 \ No newline at end of file +5.8.56 \ No newline at end of file diff --git a/app/DataMapper/Analytics/RevenueTrack.php b/app/DataMapper/Analytics/RevenueTrack.php index 6689f548ee..5a160469ab 100644 --- a/app/DataMapper/Analytics/RevenueTrack.php +++ b/app/DataMapper/Analytics/RevenueTrack.php @@ -30,7 +30,7 @@ class RevenueTrack extends GenericMixedMetric * The name of the counter. * @var string */ - public $name = 'app.revenue'; + public $name = 'app.cac'; /** * The datetime of the counter measurement. @@ -59,14 +59,14 @@ class RevenueTrack extends GenericMixedMetric * * @var string */ - public $string_metric7 = 'product'; + public $string_metric7 = 'plan'; /** * Gateway Reference * * @var string */ - public $string_metric8 = 'gateway_reference'; + public $string_metric8 = 'plan_term'; public $string_metric9 = 'entity_reference'; diff --git a/app/DataMapper/EDoc/FatturaPA.php b/app/DataMapper/EDoc/FatturaPA.php index 4153c3d312..0283cb3720 100644 --- a/app/DataMapper/EDoc/FatturaPA.php +++ b/app/DataMapper/EDoc/FatturaPA.php @@ -13,25 +13,19 @@ namespace App\DataMapper\EDoc; use Spatie\LaravelData\Data; -use Spatie\LaravelData\Optional; -use App\DataMapper\EDoc\FatturaPA\DatiContratto; -use App\DataMapper\EDoc\FatturaPA\DatiRicezione; -use App\DataMapper\EDoc\FatturaPA\DatiOrdineAcquisto; -use App\DataMapper\EDoc\FatturaPA\DatiAnagraficiVettore; +use App\DataMapper\EDoc\FatturaPA\FatturaElettronicaHeader; +use App\DataMapper\EDoc\FatturaPA\FatturaElettronicaBody; + + +// minimum required fields +// public string $RegimeFiscale = 'RF01', +// public string $TipoDocumento = 'TD01', +// public string $ModalitaPagamento = 'MP01', +// public string $CondizioniPagamento = 'TP02', class FatturaPA extends Data { - public DatiRicezione|Optional $DatiRicezione; - public DatiContratto|Optional $DatiContratto; - public DatiOrdineAcquisto|Optional $DatiOrdineAcquisto; - public DatiAnagraficiVettore|Optional $DatiAnagraficiVettore; - - public function __construct( - public string $RegimeFiscale = 'RF01', - public string $TipoDocumento = 'TD01', - public string $ModalitaPagamento = 'MP01', - public string $CondizioniPagamento = 'TP02', - ) { - } + public FatturaElettronicaHeader $FatturaElettronicaHeader; + public FatturaElettronicaBody $FatturaElettronicaBody; } diff --git a/app/DataMapper/EDoc/FatturaPA/Allegati.php b/app/DataMapper/EDoc/FatturaPA/Allegati.php new file mode 100644 index 0000000000..c8ca2a09cc --- /dev/null +++ b/app/DataMapper/EDoc/FatturaPA/Allegati.php @@ -0,0 +1,40 @@ + + // + // + #[Regex('/^[\-]?[0-9]{1,11}\.[0-9]{2}$/')] + public float $AliquotaRitenuta; + + /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */ + #[Max(2)] + public string $CausalePagamento; + +} diff --git a/app/DataMapper/EDoc/FatturaPA/Body/ScontoMaggiorazione.php b/app/DataMapper/EDoc/FatturaPA/Body/ScontoMaggiorazione.php new file mode 100644 index 0000000000..6f7fd40921 --- /dev/null +++ b/app/DataMapper/EDoc/FatturaPA/Body/ScontoMaggiorazione.php @@ -0,0 +1,33 @@ +DataOraConsegna = new \DateTime(); + // $this->DataInizioTrasporto = new \DateTime(); + // $this->DataInizioTrasporto = new \DateTime(); +// } + +} diff --git a/app/DataMapper/EDoc/FatturaPA/DatiVeicoli.php b/app/DataMapper/EDoc/FatturaPA/DatiVeicoli.php new file mode 100644 index 0000000000..6933ecfd7d --- /dev/null +++ b/app/DataMapper/EDoc/FatturaPA/DatiVeicoli.php @@ -0,0 +1,32 @@ +Data = new \DateTime(); + } +} \ No newline at end of file diff --git a/app/DataMapper/EDoc/FatturaPA/DettaglioLinee.php b/app/DataMapper/EDoc/FatturaPA/DettaglioLinee.php new file mode 100644 index 0000000000..960330b364 --- /dev/null +++ b/app/DataMapper/EDoc/FatturaPA/DettaglioLinee.php @@ -0,0 +1,77 @@ + + // + // + // 0-100 + public float $AliquotaIVA; + + //string 2 char options + public string|Optional $TipoCessionePrestazione; + + public CodiceArticolo|Optional $CodiceArticolo; + + // + // + public float|Optional $Quantita; + + //String10Type + public string|Optional $UnitaMisura; + + //date + #[WithTransformer(DateTimeInterfaceTransformer::class, format: 'Y-m-d')] + public \Illuminate\Support\Carbon|Optional $DataInizioPeriodo; + + //date + #[WithTransformer(DateTimeInterfaceTransformer::class, format: 'Y-m-d')] + public \Illuminate\Support\Carbon|Optional $DataFinePeriodo; + + public ScontoMaggiorazione|Optional $ScontoMaggiorazione; + + //4 char options + public string|Optional $Ritenuta; + + //string options + public string|Optional $Natura; + + //string 20 char + public string|Optional $RiferimentoAmministrazione; + + public AltriDatiGestionali|Optional $AltriDatiGestionali; + + +} + diff --git a/app/DataMapper/EDoc/FatturaPA/DettaglioPagamento.php b/app/DataMapper/EDoc/FatturaPA/DettaglioPagamento.php new file mode 100644 index 0000000000..fb058afd4f --- /dev/null +++ b/app/DataMapper/EDoc/FatturaPA/DettaglioPagamento.php @@ -0,0 +1,92 @@ + + // + // + public int|Optional $GiorniTerminiPagamento; + + //date + #[WithTransformer(DateTimeInterfaceTransformer::class, format: 'Y-m-d')] + public \Illuminate\Support\Carbon|Optional $DataScadenzaPagamento; + + //String20Type + public string|Optional $CodUfficioPostale; + + //String60LatinType + public string|Optional $CognomeQuietanzante; + + //String60LatinType + public string|Optional $NomeQuietanzante; + + //string [A-Z0-9]{16} + public string|Optional $CFQuietanzante; + + //string {IsBasicLatin}{2,10} + public string|Optional $TitoloQuietanzante; + + //string String80LatinType + public string|Optional $IstitutoFinanziario; + + //[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{11,30} + public string|Optional $IBAN; + + // string [0-9][0-9][0-9][0-9][0-9] + public string|Optional $ABI; + + //[0-9][0-9][0-9][0-9][0-9] + public string|Optional $CAB; + + //[A-Z]{6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3}){0,1} + public string|Optional $BIC; + + //Amount2DecimalType + public float|Optional $ScontoPagamentoAnticipato; + + //Date + #[WithTransformer(DateTimeInterfaceTransformer::class, format: 'Y-m-d')] + public \Illuminate\Support\Carbon|Optional $DataLimitePagamentoAnticipato; + + //Amount2DecimalType + public float|Optional $PenalitaPagamentiRitardati; + + //date + #[WithTransformer(DateTimeInterfaceTransformer::class, format: 'Y-m-d')] + public \Illuminate\Support\Carbon|Optional $DataDecorrenzaPenale; + + //String60Type + public string|Optional $CodicePagamento; + +} \ No newline at end of file diff --git a/app/DataMapper/EDoc/FatturaPA/FatturaElettronicaBody.php b/app/DataMapper/EDoc/FatturaPA/FatturaElettronicaBody.php new file mode 100644 index 0000000000..90603edb6a --- /dev/null +++ b/app/DataMapper/EDoc/FatturaPA/FatturaElettronicaBody.php @@ -0,0 +1,29 @@ + + public string|Optional $CodiceFiscaleType; +} diff --git a/app/DataMapper/EDoc/FatturaPA/Sede.php b/app/DataMapper/EDoc/FatturaPA/Sede.php new file mode 100644 index 0000000000..0f85813fad --- /dev/null +++ b/app/DataMapper/EDoc/FatturaPA/Sede.php @@ -0,0 +1,30 @@ +data, false); + + // return json_decode($this->data, true); + } +} \ No newline at end of file diff --git a/app/Helpers/Generic.php b/app/Helpers/Generic.php index 651d040349..33c5b4ba80 100644 --- a/app/Helpers/Generic.php +++ b/app/Helpers/Generic.php @@ -44,3 +44,29 @@ function nlog($output, $context = []): void $output = null; $context = null; } + + +function nrlog($output, $context = []): void +{ + if (! config('ninja.expanded_logging')) { + return; + } + + if (gettype($output) == 'object') { + $output = print_r($output, 1); + } + + // $trace = debug_backtrace(); + + if (Ninja::isHosted()) { + try { + info($output); + } catch (\Exception $e) { + } + } else { + \Illuminate\Support\Facades\Log::channel('invoiceninja-reminders')->info($output, $context); + } + + $output = null; + $context = null; +} diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index fe6485a8ea..d3b1d56c6d 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -11,36 +11,37 @@ namespace App\Http\Controllers; -use App\Models\Account; -use App\Models\BankIntegration; -use App\Models\BankTransaction; -use App\Models\BankTransactionRule; +use App\Models\User; +use App\Utils\Ninja; use App\Models\Client; -use App\Models\CompanyGateway; use App\Models\Design; -use App\Models\ExpenseCategory; -use App\Models\GroupSetting; -use App\Models\PaymentTerm; +use App\Utils\Statics; +use App\Models\Account; +use App\Models\TaxRate; +use App\Models\Webhook; use App\Models\Scheduler; use App\Models\TaskStatus; -use App\Models\TaxRate; -use App\Models\User; -use App\Models\Webhook; -use App\Transformers\ArraySerializer; -use App\Transformers\EntityTransformer; -use App\Utils\Ninja; -use App\Utils\Statics; -use App\Utils\Traits\AppSetup; -use Illuminate\Contracts\Container\BindingResolutionException; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Http\Response; -use Illuminate\Support\Facades\Auth; +use App\Models\PaymentTerm; use Illuminate\Support\Str; use League\Fractal\Manager; -use League\Fractal\Pagination\IlluminatePaginatorAdapter; -use League\Fractal\Resource\Collection; +use App\Models\GroupSetting; +use Illuminate\Http\Response; +use App\Models\CompanyGateway; +use App\Utils\Traits\AppSetup; +use App\Models\BankIntegration; +use App\Models\BankTransaction; +use App\Models\ExpenseCategory; use League\Fractal\Resource\Item; +use App\DataMapper\EDoc\Schema\RO; +use App\Models\BankTransactionRule; +use Illuminate\Support\Facades\Auth; +use App\Transformers\ArraySerializer; +use App\Transformers\EntityTransformer; +use League\Fractal\Resource\Collection; +use Illuminate\Database\Eloquent\Builder; use League\Fractal\Serializer\JsonApiSerializer; +use League\Fractal\Pagination\IlluminatePaginatorAdapter; +use Illuminate\Contracts\Container\BindingResolutionException; /** * Class BaseController. @@ -993,7 +994,17 @@ class BaseController extends Controller /** @var \App\Models\User $user */ $user = auth()->user(); - $response['static'] = Statics::company($user->getCompany()->getLocale()); + $response_data = Statics::company($user->getCompany()->getLocale()); + + if(request()->has('einvoice')){ + + $ro = new RO(); + $response_data['einvoice_schema'] = $ro(); + + } + + $response['static'] = $response_data; + } } diff --git a/app/Http/Controllers/StaticController.php b/app/Http/Controllers/StaticController.php index a8f8e4ad1d..1456534362 100644 --- a/app/Http/Controllers/StaticController.php +++ b/app/Http/Controllers/StaticController.php @@ -11,6 +11,7 @@ namespace App\Http\Controllers; +use App\DataMapper\EDoc\Schema\RO; use App\Utils\Statics; use Illuminate\Http\Response; @@ -56,8 +57,15 @@ class StaticController extends BaseController /** @var \App\Models\User $user */ $user = auth()->user(); - $response = Statics::company($user->getLocale() ?? $user->company()->getLocale()); + $response_data = Statics::company($user->getLocale() ?? $user->company()->getLocale()); - return response()->json($response, 200, ['Content-type' => 'application/json; charset=utf-8'], JSON_PRETTY_PRINT); + if(request()->has('einvoice')){ + + $ro = new RO; + + $response_data['einvoice_schema'] = $ro(); + } + + return response()->json($response_data, 200, ['Content-type' => 'application/json; charset=utf-8'], JSON_PRETTY_PRINT); } } diff --git a/app/Http/Requests/Credit/StoreCreditRequest.php b/app/Http/Requests/Credit/StoreCreditRequest.php index 534a7bc77e..8d6240c4c3 100644 --- a/app/Http/Requests/Credit/StoreCreditRequest.php +++ b/app/Http/Requests/Credit/StoreCreditRequest.php @@ -78,6 +78,8 @@ class StoreCreditRequest extends Request $rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; +$rules['date'] = 'bail|sometimes|date:Y-m-d'; + if ($this->invoice_id) { $rules['invoice_id'] = new ValidInvoiceCreditRule(); } diff --git a/app/Http/Requests/Credit/UpdateCreditRequest.php b/app/Http/Requests/Credit/UpdateCreditRequest.php index bfbd1f268d..91a1608fe0 100644 --- a/app/Http/Requests/Credit/UpdateCreditRequest.php +++ b/app/Http/Requests/Credit/UpdateCreditRequest.php @@ -68,7 +68,9 @@ class UpdateCreditRequest extends Request $rules['line_items'] = 'array'; -$rules['discount'] = 'sometimes|numeric|max:99999999999999'; + $rules['date'] = 'bail|sometimes|date:Y-m-d'; + + $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['is_amount_discount'] = ['boolean']; $rules['tax_rate1'] = 'bail|sometimes|numeric'; $rules['tax_rate2'] = 'bail|sometimes|numeric'; diff --git a/app/Http/Requests/Invoice/StoreInvoiceRequest.php b/app/Http/Requests/Invoice/StoreInvoiceRequest.php index f7bcb565d8..54dae6e20b 100644 --- a/app/Http/Requests/Invoice/StoreInvoiceRequest.php +++ b/app/Http/Requests/Invoice/StoreInvoiceRequest.php @@ -66,6 +66,8 @@ class StoreInvoiceRequest extends Request $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; $rules['is_amount_discount'] = ['boolean']; + $rules['date'] = 'bail|sometimes|date:Y-m-d'; + $rules['line_items'] = 'array'; $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['tax_rate1'] = 'bail|sometimes|numeric'; diff --git a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php index c06605cf61..0e75760a66 100644 --- a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php +++ b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php @@ -80,6 +80,8 @@ $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['partial'] = 'bail|sometimes|nullable|numeric'; $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; +$rules['date'] = 'bail|sometimes|date:Y-m-d'; + // $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date']; // $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date']; diff --git a/app/Http/Requests/Quote/StoreQuoteRequest.php b/app/Http/Requests/Quote/StoreQuoteRequest.php index 221ea38153..c8d0a02035 100644 --- a/app/Http/Requests/Quote/StoreQuoteRequest.php +++ b/app/Http/Requests/Quote/StoreQuoteRequest.php @@ -61,10 +61,11 @@ class StoreQuoteRequest extends Request $rules['number'] = ['nullable', Rule::unique('quotes')->where('company_id', $user->company()->id)]; -$rules['discount'] = 'sometimes|numeric|max:99999999999999'; + $rules['discount'] = 'sometimes|numeric|max:99999999999999'; $rules['is_amount_discount'] = ['boolean']; $rules['exchange_rate'] = 'bail|sometimes|numeric'; $rules['line_items'] = 'array'; + $rules['date'] = 'bail|sometimes|date:Y-m-d'; $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date', 'after_or_equal:date']; $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date']; $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; diff --git a/app/Http/Requests/Quote/UpdateQuoteRequest.php b/app/Http/Requests/Quote/UpdateQuoteRequest.php index d1e3fe9967..4f9986df2e 100644 --- a/app/Http/Requests/Quote/UpdateQuoteRequest.php +++ b/app/Http/Requests/Quote/UpdateQuoteRequest.php @@ -63,6 +63,8 @@ class UpdateQuoteRequest extends Request $rules['is_amount_discount'] = ['boolean']; $rules['exchange_rate'] = 'bail|sometimes|numeric'; + $rules['date'] = 'bail|sometimes|date:Y-m-d'; + $rules['partial_due_date'] = ['bail', 'sometimes', 'exclude_if:partial,0', Rule::requiredIf(fn () => $this->partial > 0), 'date', 'before:due_date']; $rules['due_date'] = ['bail', 'sometimes', 'nullable', 'after:partial_due_date', 'after_or_equal:date', Rule::requiredIf(fn () => strlen($this->partial_due_date) > 1), 'date']; $rules['amount'] = ['sometimes', 'bail', 'numeric', 'max:99999999999999']; diff --git a/app/Jobs/Credit/ApplyCreditPayment.php b/app/Jobs/Credit/ApplyCreditPayment.php index 211fe4383d..d2ebc361ef 100644 --- a/app/Jobs/Credit/ApplyCreditPayment.php +++ b/app/Jobs/Credit/ApplyCreditPayment.php @@ -11,13 +11,16 @@ namespace App\Jobs\Credit; +use App\Utils\Number; use App\Models\Credit; use App\Models\Payment; use Illuminate\Bus\Queueable; +use Illuminate\Support\Carbon; +use App\DataMapper\InvoiceItem; +use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; class ApplyCreditPayment implements ShouldQueue { @@ -67,6 +70,19 @@ class ApplyCreditPayment implements ShouldQueue $credit_balance = $this->credit->balance; + $item_date = Carbon::parse($this->payment->date)->format($this->payment->client->date_format()); + $invoice_numbers = $this->payment->invoices->pluck('number')->implode(","); + + $item = new InvoiceItem(); + $item->quantity = 0; + $item->cost = $this->amount * -1; + $item->notes = "{$item_date} - " . ctrans('texts.credit_payment', ['invoice_number' => $invoice_numbers]) . " ". Number::formatMoney($this->amount, $this->payment->client); + $item->type_id = "1"; + + $line_items = $this->credit->line_items; + $line_items[] = $item; + $this->credit->line_items = $line_items; + if ($this->amount == $credit_balance) { //total credit applied. $this->credit ->service() @@ -90,7 +106,7 @@ class ApplyCreditPayment implements ShouldQueue ->client ->service() ->adjustCreditBalance($this->amount * -1) - ->save(); + ->save(); /* Update Payment Applied Amount*/ $this->payment->save(); diff --git a/app/Jobs/Invoice/CreateUbl.php b/app/Jobs/Invoice/CreateUbl.php index f5d80fd193..5787fda50c 100644 --- a/app/Jobs/Invoice/CreateUbl.php +++ b/app/Jobs/Invoice/CreateUbl.php @@ -103,6 +103,7 @@ class CreateUbl implements ShouldQueue $ubl_invoice->setLegalMonetaryTotal((new LegalMonetaryTotal()) //->setLineExtensionAmount() + ->setTaxInclusiveAmount($taxtotal->getTaxAmount()) ->setTaxExclusiveAmount($taxable) ->setPayableAmount($invoice->balance)); diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index ac3f6e45dd..64c0ebce92 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -56,7 +56,7 @@ class ReminderJob implements ShouldQueue Auth::logout(); if (! config('ninja.db.multi_db_enabled')) { - nlog("Sending invoice reminders on ".now()->format('Y-m-d h:i:s')); + nrlog("Sending invoice reminders on ".now()->format('Y-m-d h:i:s')); Invoice::query() ->where('is_deleted', 0) @@ -84,7 +84,7 @@ class ReminderJob implements ShouldQueue foreach (MultiDB::$dbs as $db) { MultiDB::setDB($db); - nlog("Sending invoice reminders on db {$db} ".now()->format('Y-m-d h:i:s')); + nrlog("Sending invoice reminders on db {$db} ".now()->format('Y-m-d h:i:s')); Invoice::query() ->where('is_deleted', 0) @@ -121,12 +121,12 @@ class ReminderJob implements ShouldQueue if ($invoice->isPayable()) { //Attempts to prevent duplicates from sending if ($invoice->reminder_last_sent && Carbon::parse($invoice->reminder_last_sent)->startOfDay()->eq(now()->startOfDay())) { - nlog("caught a duplicate reminder for invoice {$invoice->number}"); + nrlog("caught a duplicate reminder for invoice {$invoice->number}"); return; } $reminder_template = $invoice->calculateTemplate('invoice'); - nlog("reminder template = {$reminder_template}"); + nrlog("reminder template = {$reminder_template}"); $invoice->service()->touchReminder($reminder_template)->save(); $fees = $this->calcLateFee($invoice, $reminder_template); @@ -149,7 +149,7 @@ class ReminderJob implements ShouldQueue $invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) { if ($invitation->contact && !$invitation->contact->trashed() && $invitation->contact->email) { EmailEntity::dispatch($invitation, $invitation->company, $reminder_template); - nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}"); + nrlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}"); $invoice->entityEmailEvent($invitation, $reminder_template); $invoice->sendEvent(Webhook::EVENT_REMIND_INVOICE, "client"); } @@ -220,7 +220,7 @@ class ReminderJob implements ShouldQueue $invoice->invitations->each(function ($invitation) use ($invoice, $reminder_template) { if ($invitation->contact && !$invitation->contact->trashed() && $invitation->contact->email) { EmailEntity::dispatch($invitation, $invitation->company, $reminder_template); - nlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}"); + nrlog("Firing reminder email for invoice {$invoice->number} - {$reminder_template}"); $invoice->entityEmailEvent($invitation, $reminder_template); $invoice->sendEvent(Webhook::EVENT_REMIND_INVOICE, "client"); } diff --git a/app/Repositories/TaskRepository.php b/app/Repositories/TaskRepository.php index 2eb402d097..c95207c25a 100644 --- a/app/Repositories/TaskRepository.php +++ b/app/Repositories/TaskRepository.php @@ -262,6 +262,9 @@ class TaskRepository extends BaseRepository if($this->task_round_up) return $start_time + (int)ceil($interval/$this->task_round_to_nearest)*$this->task_round_to_nearest; + if($interval <= $this->task_round_to_nearest) + return $start_time; + return $start_time - (int)floor($interval/$this->task_round_to_nearest) * $this->task_round_to_nearest; } diff --git a/app/Services/Client/Statement.php b/app/Services/Client/Statement.php index 8c4bea7878..a1a93fc900 100644 --- a/app/Services/Client/Statement.php +++ b/app/Services/Client/Statement.php @@ -375,7 +375,8 @@ class Statement ->whereIn('status_id', [Credit::STATUS_SENT, Credit::STATUS_PARTIAL, Credit::STATUS_APPLIED]) ->whereBetween('date', [Carbon::parse($this->options['start_date']), Carbon::parse($this->options['end_date'])]) ->where(function ($query) { - $query->whereDate('due_date', '>=', $this->options['end_date']) + // $query->whereDate('due_date', '>=', $this->options['end_date']) + $query->whereDate('due_date', '>=', now()) ->orWhereNull('due_date'); }) ->orderBy('date', 'ASC'); diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 4434729877..0476aae980 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -488,7 +488,7 @@ class InvoiceService /*When a reminder is sent we want to touch the dates they were sent*/ public function touchReminder(string $reminder_template) - { + { nrlog(now()->format('Y-m-d h:i:s') . " INV #{$this->invoice->number} : Touching Reminder => {$reminder_template}"); switch ($reminder_template) { case 'reminder1': $this->invoice->reminder1_sent = now(); diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index 8af23142ba..2d55d8ad96 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -822,8 +822,16 @@ class TemplateService $credits = collect($credits) ->map(function ($credit) { + $payments = []; + $this->entity = $credit; + if($credit->payments ?? false) { + $payments = $credit->payments->map(function ($payment) { + return $this->transformPayment($payment); + })->toArray(); + } + return [ 'amount' => Number::formatMoney($credit->amount, $credit->client), 'balance' => Number::formatMoney($credit->balance, $credit->client), @@ -879,7 +887,7 @@ class TemplateService 'vat_number' => $credit->client->vat_number ?? '', 'currency' => $credit->client->currency()->code ?? 'USD', ], - 'payments' => [], + 'payments' => $payments, 'total_tax_map' => $credit->calc()->getTotalTaxMap(), 'line_tax_map' => $credit->calc()->getTaxMap(), ]; diff --git a/config/data.php b/config/data.php index 2095a5d856..a17b041bdf 100644 --- a/config/data.php +++ b/config/data.php @@ -6,7 +6,10 @@ return [ * is an array, it will try to convert from the first format that works, * and will serialize dates using the first format from the array. */ - 'date_format' => DATE_ATOM, + 'date_format' => [ + 'Y-m-d', + 'Y-m-d\TH:i:s.uP', + ], /* * Global transformers will take complex types and transform them into simple diff --git a/config/logging.php b/config/logging.php index 9a4f1f01f4..b9f74aa68b 100644 --- a/config/logging.php +++ b/config/logging.php @@ -58,7 +58,12 @@ return [ 'level' => env('LOG_LEVEL', 'debug'), 'days' => 7, ], - + 'invoiceninja-reminders' => [ + 'driver' => 'single', + 'path' => storage_path('logs/invoiceninja-reminders.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'days' => 90, + ], 'stack' => [ 'driver' => 'stack', 'channels' => ['single'], diff --git a/config/ninja.php b/config/ninja.php index c2b2ee8583..94445f5394 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.8.54'), - 'app_tag' => env('APP_TAG', '5.8.54'), + 'app_version' => env('APP_VERSION', '5.8.56'), + 'app_tag' => env('APP_TAG', '5.8.56'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false), diff --git a/resources/views/portal/ninja2020/gateways/stripe/acss/authorize.blade.php b/resources/views/portal/ninja2020/gateways/stripe/acss/authorize.blade.php index c88bc2bbad..ee9b21d32f 100644 --- a/resources/views/portal/ninja2020/gateways/stripe/acss/authorize.blade.php +++ b/resources/views/portal/ninja2020/gateways/stripe/acss/authorize.blade.php @@ -60,7 +60,7 @@