Merge pull request #8258 from turbo124/v5-develop

Attach recurring invoice docs
This commit is contained in:
David Bomba 2023-02-07 23:39:01 +11:00 committed by GitHub
commit eff0945c08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 122 additions and 42 deletions

View File

@ -10,9 +10,7 @@
## [Hosted](https://www.invoiceninja.com) | [Self-Hosted](https://www.invoiceninja.org) ## [Hosted](https://www.invoiceninja.com) | [Self-Hosted](https://www.invoiceninja.org)
Join us on [Slack](http://slack.invoiceninja.com), [Discord](https://discord.com/channels/1071654583870435439/1071654584390537279) [Discourse](https://forum.invoiceninja.com) - Join us on [Slack](http://slack.invoiceninja.com), [Discord](https://discord.gg/ZwEdtfCwXA), [Support Forum](https://forum.invoiceninja.com)
or [StackOverflow](https://stackoverflow.com/tags/invoice-ninja/) if you like,
just make sure to add the `invoice-ninja` tag to your question.
## Introduction ## Introduction
@ -27,13 +25,13 @@ We offer a $30 per year white-label license to remove the Invoice Ninja branding
* [API Documentation](https://app.swaggerhub.com/apis/invoiceninja/invoiceninja) * [API Documentation](https://app.swaggerhub.com/apis/invoiceninja/invoiceninja)
* [APP Documentation](https://invoiceninja.github.io/) * [APP Documentation](https://invoiceninja.github.io/)
* [Support Forum](https://forum.invoiceninja.com) * [Support Forum](https://forum.invoiceninja.com)
* [StackOverflow](https://stackoverflow.com/tags/invoice-ninja/)
## Setup ## Setup
### Mobile Apps ### Mobile Apps
* [iPhone](https://apps.apple.com/app/id1503970375?platform=iphone) * [iPhone](https://apps.apple.com/app/id1503970375?platform=iphone)
* [Android](https://play.google.com/store/apps/details?id=com.invoiceninja.app) * [Android](https://play.google.com/store/apps/details?id=com.invoiceninja.app)
* [F-Droid](https://f-droid.org/en/packages/com.invoiceninja.app)
### Desktop Apps ### Desktop Apps
* [macOS](https://apps.apple.com/app/id1503970375?platform=mac) * [macOS](https://apps.apple.com/app/id1503970375?platform=mac)
@ -55,7 +53,7 @@ We offer a $30 per year white-label license to remove the Invoice Ninja branding
git clone https://github.com/invoiceninja/invoiceninja.git git clone https://github.com/invoiceninja/invoiceninja.git
git checkout v5-stable git checkout v5-stable
cp .env.example .env cp .env.example .env
composer update composer i -o --no-dev
php artisan key:generate php artisan key:generate
``` ```

View File

@ -1 +1 @@
5.5.68 5.5.69

View File

@ -1031,6 +1031,11 @@ class BaseController extends Controller
public function flutterRoute() public function flutterRoute()
{ {
if ((bool) $this->checkAppSetup() !== false && $account = Account::first()) { if ((bool) $this->checkAppSetup() !== false && $account = Account::first()) {
//always redirect invoicing.co to invoicing.co
if(Ninja::isHosted() && (request()->getSchemeAndHttpHost() != 'https://invoicing.co'))
return redirect()->secure('https://invoicing.co');
if (config('ninja.require_https') && ! request()->isSecure()) { if (config('ninja.require_https') && ! request()->isSecure()) {
return redirect()->secure(request()->getRequestUri()); return redirect()->secure(request()->getRequestUri());
} }

View File

@ -322,6 +322,7 @@ class BillingPortalPurchasev2 extends Component
'total' => $total, 'total' => $total,
'qty' => $qty, 'qty' => $qty,
'is_recurring' => true, 'is_recurring' => true,
'product_image' => $p->product_image,
]); ]);
} }

View File

@ -42,7 +42,7 @@ class GenericReportRequest extends Request
{ {
$input = $this->all(); $input = $this->all();
if (! array_key_exists('date_range', $input)) { if (! array_key_exists('date_range', $input) || $input['date_range'] == '') {
$input['date_range'] = 'all'; $input['date_range'] = 'all';
} }

View File

@ -46,7 +46,7 @@ class ProductSalesReportRequest extends Request
{ {
$input = $this->all(); $input = $this->all();
if (! array_key_exists('date_range', $input)) { if (! array_key_exists('date_range', $input) || $input['date_range'] == '') {
$input['date_range'] = 'all'; $input['date_range'] = 'all';
} }

View File

@ -42,7 +42,7 @@ class ProfitLossRequest extends Request
{ {
$input = $this->all(); $input = $this->all();
if (! array_key_exists('date_range', $input)) { if (! array_key_exists('date_range', $input) || $input['date_range'] == '') {
$input['date_range'] = 'all'; $input['date_range'] = 'all';
} }

View File

@ -138,6 +138,17 @@ class InvoiceEmailEngine extends BaseEmailEngine
if ($this->client->getSetting('document_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) { if ($this->client->getSetting('document_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_DOCUMENTS)) {
if($this->invoice->recurring_invoice()->exists())
{
foreach ($this->invoice->recurring_invoice->documents as $document) {
if($document->size > $this->max_attachment_size)
$this->setAttachmentLinks(["<a class='doc_links' href='" . URL::signedRoute('documents.public_download', ['document_hash' => $document->hash]) ."'>". $document->name ."</a>"]);
else
$this->setAttachments([['file' => base64_encode($document->getFile()), 'path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, ]]);
}
}
// Storage::url // Storage::url
foreach ($this->invoice->documents as $document) { foreach ($this->invoice->documents as $document) {

View File

@ -163,9 +163,9 @@ class BankTransactionRule extends BaseModel
return $this->belongsTo(User::class)->withTrashed(); return $this->belongsTo(User::class)->withTrashed();
} }
public function expense_cateogry() public function expense_category()
{ {
return $this->belongsTo(ExpenseCategory::class)->withTrashed(); return $this->belongsTo(ExpenseCategory::class, 'category_id', 'id')->withTrashed();
} }
} }

View File

@ -39,6 +39,8 @@ class Product extends BaseModel
'in_stock_quantity', 'in_stock_quantity',
'stock_notification_threshold', 'stock_notification_threshold',
'stock_notification', 'stock_notification',
'max_quantity',
'product_image',
]; ];
protected $touches = []; protected $touches = [];

View File

@ -82,7 +82,7 @@ class ClientContactObserver
CreditInvitation::withTrashed()->where('client_contact_id', $client_contact_id)->cursor()->each(function ($invite){ CreditInvitation::withTrashed()->where('client_contact_id', $client_contact_id)->cursor()->each(function ($invite){
if($invite->credits()->doesnthave('invitations')) if($invite->credit()->doesnthave('invitations'))
$invite->credit->service()->createInvitations(); $invite->credit->service()->createInvitations();
}); });

View File

@ -43,6 +43,11 @@ class CustomPaymentDriver extends BaseDriver
return $types; return $types;
} }
public function init()
{
return $this;
}
public function setPaymentMethod($payment_method_id) public function setPaymentMethod($payment_method_id)
{ {
$this->payment_method = $payment_method_id; $this->payment_method = $payment_method_id;
@ -101,4 +106,9 @@ class CustomPaymentDriver extends BaseDriver
{ {
// Driver doesn't support this feature. // Driver doesn't support this feature.
} }
public function getClientRequiredFields(): array
{
return [];
}
} }

View File

@ -36,6 +36,7 @@ class ApplyNumber extends AbstractService
public function run() public function run()
{ {
if ($this->invoice->number != '') { if ($this->invoice->number != '') {
return $this->invoice; return $this->invoice;
} }
@ -45,7 +46,7 @@ class ApplyNumber extends AbstractService
$this->trySaving(); $this->trySaving();
break; break;
case 'when_sent': case 'when_sent':
if ($this->invoice->status_id == Invoice::STATUS_SENT) { if ($this->invoice->status_id >= Invoice::STATUS_SENT) {
$this->trySaving(); $this->trySaving();
} }
break; break;

View File

@ -85,7 +85,11 @@ class UpdateInvoicePayment
if($invoice->is_proforma) if($invoice->is_proforma)
{ {
$invoice->number = '';
if(strlen($invoice->number) > 1 && str_starts_with($invoice->number,"####"))
$invoice->number = '';
$invoice->is_proforma = false; $invoice->is_proforma = false;
$invoice->service() $invoice->service()

View File

@ -958,7 +958,7 @@ class SubscriptionService
$invoice->subscription_id = $this->subscription->id; $invoice->subscription_id = $this->subscription->id;
$invoice->client_id = $client_id; $invoice->client_id = $client_id;
$invoice->is_proforma = true; $invoice->is_proforma = true;
$invoice->number = ctrans('texts.subscription') . "_" . now()->format('Y-m-d') . "_" . rand(0,100000); $invoice->number = "####" . ctrans('texts.subscription') . "_" . now()->format('Y-m-d') . "_" . rand(0,100000);
$line_items = $bundle->map(function ($item){ $line_items = $bundle->map(function ($item){
$line_item = new InvoiceItem; $line_item = new InvoiceItem;

View File

@ -11,13 +11,12 @@
namespace App\Transformers; namespace App\Transformers;
use App\Models\Account;
use App\Models\BankTransaction; use App\Models\BankTransaction;
use App\Models\BankTransactionRule; use App\Models\BankTransactionRule;
use App\Models\Company; use App\Models\Company;
use App\Models\Expense; use App\Models\ExpenseCategory;
use App\Models\Invoice;
use App\Transformers\VendorTransformer; use App\Transformers\VendorTransformer;
use App\Transformers\ExpenseCateogryTransformer;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
/** /**
@ -77,6 +76,9 @@ class BankTransactionRuleTransformer extends EntityTransformer
{ {
$transformer = new ClientTransformer($this->serializer); $transformer = new ClientTransformer($this->serializer);
if(!$bank_transaction_rule->client)
return null;
return $this->includeItem($bank_transaction_rule->expense, $transformer, Client::class); return $this->includeItem($bank_transaction_rule->expense, $transformer, Client::class);
} }
@ -84,7 +86,20 @@ class BankTransactionRuleTransformer extends EntityTransformer
{ {
$transformer = new VendorTransformer($this->serializer); $transformer = new VendorTransformer($this->serializer);
if(!$bank_transaction_rule->vendor)
return null;
return $this->includeItem($bank_transaction_rule->vendor, $transformer, Vendor::class); return $this->includeItem($bank_transaction_rule->vendor, $transformer, Vendor::class);
} }
public function includeExpenseCategory(BankTransactionRule $bank_transaction_rule)
{
$transformer = new ExpenseCategoryTransformer($this->serializer);
if(!$bank_transaction_rule->expense_cateogry)
return null;
return $this->includeItem($bank_transaction_rule->expense_category, $transformer, ExpenseCategory::class);
}
} }

View File

@ -93,6 +93,8 @@ class ProductTransformer extends EntityTransformer
'in_stock_quantity' => (int) $product->in_stock_quantity ?: 0, 'in_stock_quantity' => (int) $product->in_stock_quantity ?: 0,
'stock_notification' => (bool) $product->stock_notification, 'stock_notification' => (bool) $product->stock_notification,
'stock_notification_threshold' => (int) $product->stock_notification_threshold, 'stock_notification_threshold' => (int) $product->stock_notification_threshold,
'max_quantity' => (int) $product->max_quantity,
'product_image' => (string) $product->product_image ?: '',
]; ];
} }
} }

View File

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

View File

@ -0,0 +1,31 @@
<?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('products', function (Blueprint $table){
$table->unsignedInteger("max_quantity")->nullable();
$table->string("product_image", 191)->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
};

View File

@ -1,2 +1,2 @@
/*! For license information please see approve.js.LICENSE.txt */ /*! For license information please see approve.js.LICENSE.txt */
(()=>{function e(e,t){for(var n=0;n<t.length;n++){var u=t[n];u.enumerable=u.enumerable||!1,u.configurable=!0,"value"in u&&(u.writable=!0),Object.defineProperty(e,u.key,u)}}var t=function(){function t(e,n,u){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),this.shouldDisplaySignature=e,this.shouldDisplayTerms=n,this.shouldDisplayUserInput=u,this.termsAccepted=!1}var n,u,a;return n=t,(u=[{key:"submitForm",value:function(){document.getElementById("approve-form").submit()}},{key:"displaySignature",value:function(){document.getElementById("displaySignatureModal").removeAttribute("style");var e=new SignaturePad(document.getElementById("signature-pad"),{penColor:"rgb(0, 0, 0)"});e.onEnd=function(){document.getElementById("signature-next-step").disabled=!1},this.signaturePad=e}},{key:"displayTerms",value:function(){document.getElementById("displayTermsModal").removeAttribute("style")}},{key:"displayInput",value:function(){document.getElementById("displayInputModal").removeAttribute("style")}},{key:"handle",value:function(){var e=this;document.getElementById("signature-next-step").disabled=!0,document.getElementById("close_button").addEventListener("click",(function(){var e=document.getElementById("approve-button");e&&(e.disabled=!1)})),document.getElementById("hide_close").addEventListener("click",(function(){var e=document.getElementById("approve-button");e&&(e.disabled=!1)})),document.getElementById("approve-button").addEventListener("click",(function(){e.shouldDisplaySignature||e.shouldDisplayTerms||!e.shouldDisplayUserInput||(e.displayInput(),document.getElementById("input-next-step").addEventListener("click",(function(){document.querySelector('input[name="user_input"').value=document.getElementById("user_input").value,e.termsAccepted=!0,e.submitForm()}))),e.shouldDisplayUserInput&&e.displayInput(),e.shouldDisplaySignature&&e.shouldDisplayTerms&&(e.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){e.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=e.signaturePad.toDataURL(),document.querySelector('input[name="user_input"').value=document.getElementById("user_input").value,e.termsAccepted=!0,e.submitForm()}))}))),e.shouldDisplaySignature&&!e.shouldDisplayTerms&&(e.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=e.signaturePad.toDataURL(),document.querySelector('input[name="user_input"').value=document.getElementById("user_input").value,e.submitForm()}))),!e.shouldDisplaySignature&&e.shouldDisplayTerms&&(e.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){e.termsAccepted=!0,e.submitForm()}))),e.shouldDisplaySignature||e.shouldDisplayTerms||!e.shouldDisplayUserInput||e.submitForm()}))}}])&&e(n.prototype,u),a&&e(n,a),Object.defineProperty(n,"prototype",{writable:!1}),t}(),n=document.querySelector('meta[name="require-quote-signature"]').content,u=document.querySelector('meta[name="show-quote-terms"]').content,a=document.querySelector('meta[name="accept-user-input"]').content;new t(Boolean(+n),Boolean(+u),Boolean(+a)).handle()})(); (()=>{function e(e,t){for(var n=0;n<t.length;n++){var u=t[n];u.enumerable=u.enumerable||!1,u.configurable=!0,"value"in u&&(u.writable=!0),Object.defineProperty(e,u.key,u)}}var t=function(){function t(e,n,u){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),this.shouldDisplaySignature=e,this.shouldDisplayTerms=n,this.shouldDisplayUserInput=u,this.termsAccepted=!1}var n,u,a;return n=t,(u=[{key:"submitForm",value:function(){document.getElementById("approve-form").submit()}},{key:"displaySignature",value:function(){document.getElementById("displaySignatureModal").removeAttribute("style");var e=new SignaturePad(document.getElementById("signature-pad"),{penColor:"rgb(0, 0, 0)"});e.onEnd=function(){document.getElementById("signature-next-step").disabled=!1},this.signaturePad=e}},{key:"displayTerms",value:function(){document.getElementById("displayTermsModal").removeAttribute("style")}},{key:"displayInput",value:function(){document.getElementById("displayInputModal").removeAttribute("style")}},{key:"handle",value:function(){var e=this;document.getElementById("signature-next-step").disabled=!0,document.getElementById("close_button").addEventListener("click",(function(){var e=document.getElementById("approve-button");e&&(e.disabled=!1)})),document.getElementById("hide_close").addEventListener("click",(function(){var e=document.getElementById("approve-button");e&&(e.disabled=!1)})),document.getElementById("approve-button").addEventListener("click",(function(){e.shouldDisplaySignature||e.shouldDisplayTerms||!e.shouldDisplayUserInput||(e.displayInput(),document.getElementById("input-next-step").addEventListener("click",(function(){document.querySelector('input[name="user_input"').value=document.getElementById("user_input").value,e.termsAccepted=!0,e.submitForm()}))),e.shouldDisplayUserInput&&e.displayInput(),e.shouldDisplaySignature&&e.shouldDisplayTerms&&(e.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){e.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=e.signaturePad.toDataURL(),document.querySelector('input[name="user_input"').value=document.getElementById("user_input").value,e.termsAccepted=!0,e.submitForm()}))}))),e.shouldDisplaySignature&&!e.shouldDisplayTerms&&(e.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=e.signaturePad.toDataURL(),document.querySelector('input[name="user_input"').value=document.getElementById("user_input").value,e.submitForm()}))),!e.shouldDisplaySignature&&e.shouldDisplayTerms&&(e.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){e.termsAccepted=!0,e.submitForm()}))),e.shouldDisplaySignature||e.shouldDisplayTerms||e.shouldDisplayUserInput||e.submitForm()}))}}])&&e(n.prototype,u),a&&e(n,a),Object.defineProperty(n,"prototype",{writable:!1}),t}(),n=document.querySelector('meta[name="require-quote-signature"]').content,u=document.querySelector('meta[name="show-quote-terms"]').content,a=document.querySelector('meta[name="accept-user-input"]').content;new t(Boolean(+n),Boolean(+u),Boolean(+a)).handle()})();

View File

@ -14,7 +14,7 @@
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=0274ab4f8d2b411f2a2fe5142301e7af", "/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=0274ab4f8d2b411f2a2fe5142301e7af",
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=4bd34a0b160f6f29b3096d870ac4d308", "/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=4bd34a0b160f6f29b3096d870ac4d308",
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=6fb63bae43d077b5061f4dadfe8dffc8", "/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=6fb63bae43d077b5061f4dadfe8dffc8",
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=61a346e1977d3a1fec3634b234baa25c", "/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=2cb18f2df99d0eca47fa34f1d652c34f",
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=809de47258a681f0ffebe787dd6a9a93", "/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=809de47258a681f0ffebe787dd6a9a93",
"/js/setup/setup.js": "/js/setup/setup.js?id=27560b012f166f8b9417ced2188aab70", "/js/setup/setup.js": "/js/setup/setup.js?id=27560b012f166f8b9417ced2188aab70",
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314fb8357e5be63b", "/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314fb8357e5be63b",

View File

@ -75,7 +75,7 @@ class Approve {
.getElementById('approve-button') .getElementById('approve-button')
.addEventListener('click', () => { .addEventListener('click', () => {
if (!this.shouldDisplaySignature && !this.shouldDisplayTerms && this.shouldDisplayUserInput){ if (!this.shouldDisplaySignature && !this.shouldDisplayTerms && this.shouldDisplayUserInput){
this.displayInput(); this.displayInput();
document document
@ -146,7 +146,7 @@ class Approve {
}); });
} }
if (!this.shouldDisplaySignature && !this.shouldDisplayTerms && this.shouldDisplayUserInput) { if (!this.shouldDisplaySignature && !this.shouldDisplayTerms && !this.shouldDisplayUserInput) {
this.submitForm(); this.submitForm();
} }
}); });

View File

@ -36,9 +36,9 @@
@if(!empty($subscription->recurring_product_ids)) @if(!empty($subscription->recurring_product_ids))
@foreach($recurring_products as $index => $product) @foreach($recurring_products as $index => $product)
<li class="flex py-6"> <li class="flex py-6">
@if(filter_var($product->custom_value1, FILTER_VALIDATE_URL)) @if(filter_var($product->product_image, FILTER_VALIDATE_URL))
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2"> <div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
<img src="{{$product->custom_value1}}" alt="" class="h-full w-full object-cover object-center p-2"> <img src="{{$product->product_image}}" alt="" class="h-full w-full object-cover object-center p-2">
</div> </div>
@endif @endif
<div class="ml-0 flex flex-1 flex-col"> <div class="ml-0 flex flex-1 flex-col">
@ -74,7 +74,7 @@
@endfor @endfor
} }
@else @else
@for ($i = 2; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity, max(100,$product->custom_value2)) : max(100,$product->custom_value2)); $i++) @for ($i = 2; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity, max(100,$product->max_quantity)) : max(100,$product->max_quantity)); $i++)
<option value="{{$i}}">{{$i}}</option> <option value="{{$i}}">{{$i}}</option>
@endfor @endfor
@endif @endif
@ -96,9 +96,9 @@
@if(!empty($subscription->product_ids)) @if(!empty($subscription->product_ids))
@foreach($products as $product) @foreach($products as $product)
<li class="flex py-6"> <li class="flex py-6">
@if(filter_var($product->custom_value1, FILTER_VALIDATE_URL)) @if(filter_var($product->product_image, FILTER_VALIDATE_URL))
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2"> <div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
<img src="{{$product->custom_value1}}" alt="" class="h-full w-full object-cover object-center p-2"> <img src="{{$product->product_image}}" alt="" class="h-full w-full object-cover object-center p-2">
</div> </div>
@endif @endif
<div class="ml-0 flex flex-1 flex-col"> <div class="ml-0 flex flex-1 flex-col">
@ -135,9 +135,9 @@
@if(!empty($subscription->optional_recurring_product_ids)) @if(!empty($subscription->optional_recurring_product_ids))
@foreach($optional_recurring_products as $index => $product) @foreach($optional_recurring_products as $index => $product)
<li class="flex py-6"> <li class="flex py-6">
@if(filter_var($product->custom_value1, FILTER_VALIDATE_URL)) @if(filter_var($product->product_image, FILTER_VALIDATE_URL))
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2"> <div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
<img src="{{$product->custom_value1}}" alt="" class="h-full w-full object-cover object-center p-2"> <img src="{{$product->product_image}}" alt="" class="h-full w-full object-cover object-center p-2">
</div> </div>
@endif @endif
<div class="ml-0 flex flex-1 flex-col"> <div class="ml-0 flex flex-1 flex-col">
@ -148,7 +148,7 @@
</div> </div>
</div> </div>
<div class="flex justify-between text-sm mt-1"> <div class="flex justify-between text-sm mt-1">
@if(is_numeric($product->custom_value2)) @if(is_numeric($product->max_quantity))
<p class="text-gray-500 w-3/4"></p> <p class="text-gray-500 w-3/4"></p>
<div class="flex place-content-end"> <div class="flex place-content-end">
@if($subscription->use_inventory_management && $product->in_stock_quantity == 0) @if($subscription->use_inventory_management && $product->in_stock_quantity == 0)
@ -162,7 +162,7 @@
@endif @endif
> >
<option value="0" selected="selected">0</option> <option value="0" selected="selected">0</option>
@for ($i = 1; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity, max(100,$product->custom_value2)) : max(100,$product->custom_value2)); $i++) @for ($i = 1; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity, max(100,$product->max_quantity)) : max(100,$product->max_quantity)); $i++)
<option value="{{$i}}">{{$i}}</option> <option value="{{$i}}">{{$i}}</option>
@endfor @endfor
</select> </select>
@ -176,9 +176,9 @@
@if(!empty($subscription->optional_product_ids)) @if(!empty($subscription->optional_product_ids))
@foreach($optional_products as $index => $product) @foreach($optional_products as $index => $product)
<li class="flex py-6"> <li class="flex py-6">
@if(filter_var($product->custom_value1, FILTER_VALIDATE_URL)) @if(filter_var($product->product_image, FILTER_VALIDATE_URL))
<div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2"> <div class="h-24 w-24 flex-shrink-0 overflow-hidden rounded-md border border-gray-200 mr-2">
<img src="{{$product->custom_value1}}" alt="" class="h-full w-full object-cover object-center p-2"> <img src="{{$product->product_image}}" alt="" class="h-full w-full object-cover object-center p-2">
</div> </div>
@endif @endif
<div class="ml-0 flex flex-1 flex-col"> <div class="ml-0 flex flex-1 flex-col">
@ -190,7 +190,7 @@
<p class="mt-1 text-sm text-gray-500"></p> <p class="mt-1 text-sm text-gray-500"></p>
</div> </div>
<div class="flex justify-between text-sm mt-1"> <div class="flex justify-between text-sm mt-1">
@if(is_numeric($product->custom_value2)) @if(is_numeric($product->max_quantity))
<p class="text-gray-500 w-3/4"></p> <p class="text-gray-500 w-3/4"></p>
<div class="flex place-content-end"> <div class="flex place-content-end">
@if($subscription->use_inventory_management && $product->in_stock_quantity == 0) @if($subscription->use_inventory_management && $product->in_stock_quantity == 0)
@ -200,7 +200,7 @@
@endif @endif
<select wire:model.debounce.300ms="data.{{ $index }}.optional_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm"> <select wire:model.debounce.300ms="data.{{ $index }}.optional_qty" class="rounded-md border-gray-300 shadow-sm sm:text-sm">
<option value="0" selected="selected">0</option> <option value="0" selected="selected">0</option>
@for ($i = 1; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity, min(100,$product->custom_value2)) : min(100,$product->custom_value2)); $i++) @for ($i = 1; $i <= ($subscription->use_inventory_management ? min($product->in_stock_quantity, min(100,$product->max_quantity)) : min(100,$product->max_quantity)); $i++)
<option value="{{$i}}">{{$i}}</option> <option value="{{$i}}">{{$i}}</option>
@endfor @endfor
</select> </select>

View File

@ -58,7 +58,7 @@ class TaskApiTest extends TestCase
public function testTaskLockingGate() public function testTaskLockingGate()
{ {
$data = [ $data = [
'timelog' => [[1,2],[3,4]], 'timelog' => [[1,2,'a'],[3,4,'d']],
]; ];
$response = $this->withHeaders([ $response = $this->withHeaders([
@ -194,7 +194,7 @@ class TaskApiTest extends TestCase
public function testTimeLogValidation3() public function testTimeLogValidation3()
{ {
$data = [ $data = [
'timelog' => [["a","b"],["c","d"]], 'timelog' => [["a","b",'d'],["c","d",'d']],
]; ];
try { try {
@ -213,7 +213,7 @@ class TaskApiTest extends TestCase
public function testTimeLogValidation4() public function testTimeLogValidation4()
{ {
$data = [ $data = [
'timelog' => [[1,2],[3,0]], 'timelog' => [[1,2,'d'],[3,0,'d']],
]; ];
$response = $this->withHeaders([ $response = $this->withHeaders([
@ -232,8 +232,8 @@ class TaskApiTest extends TestCase
public function testStartTask() public function testStartTask()
{ {
$log = [ $log = [
[2, 1], [2, 1,'d'],
[10, 20], [10, 20,'d'],
]; ];
$last = end($log); $last = end($log);