mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge branch 'v5-develop' of https://github.com/turbo124/invoiceninja into v5-develop
This commit is contained in:
commit
67e82a733d
@ -1 +1 @@
|
||||
5.3.94
|
||||
5.3.96
|
@ -78,7 +78,7 @@ 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',
|
||||
// 'gross_line_total' => 'item.gross_line_total',
|
||||
'custom_value1' => 'item.custom_value1',
|
||||
'custom_value2' => 'item.custom_value2',
|
||||
'custom_value3' => 'item.custom_value3',
|
||||
|
95
app/Jobs/Inventory/AdjustProductInventory.php
Normal file
95
app/Jobs/Inventory/AdjustProductInventory.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Inventory;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Product;
|
||||
use App\Utils\Traits\NumberFormatter;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
//todo - ensure we are MultiDB Aware in dispatched jobs
|
||||
|
||||
class AdjustProductInventory implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public Company $company;
|
||||
|
||||
public Invoice $invoice;
|
||||
|
||||
public array $old_invoice;
|
||||
|
||||
public function __construct(Company $company, Invoice $invoice, array $old_invoice = [])
|
||||
{
|
||||
|
||||
$this->company = $company;
|
||||
$this->invoice = $invoice;
|
||||
$this->old_invoice = $old_invoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
if(count($this->old_invoice) > 0)
|
||||
return $this->existingInventoryAdjustment();
|
||||
|
||||
return $this->newInventoryAdjustment();
|
||||
|
||||
}
|
||||
|
||||
private function newInventoryAdjustment()
|
||||
{
|
||||
|
||||
$line_items = $this->invoice->line_items;
|
||||
|
||||
foreach($line_items as $item)
|
||||
{
|
||||
|
||||
$p = Product::where('product_key', $item->product_key)->where('company_id', $this->company->id)->where('in_stock_quantity', '>', 0)->first();
|
||||
$p->in_stock_quantity -= $item->quantity;
|
||||
$p->save();
|
||||
|
||||
//check threshols and notify user
|
||||
|
||||
if($p->stock_notification_threshold && $p->in_stock_quantity <= $p->stock_notification_threshold)
|
||||
$this->notifyStockLevels($p, 'product');
|
||||
elseif($this->company->stock_notification_threshold && $p->in_stock_quantity <= $this->company->stock_notification_threshold){
|
||||
$this->notifyStocklevels($p, 'company');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function existingInventoryAdjustment()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private function notifyStocklevels(Product $product, string $notification_level)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -666,8 +666,6 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
$offset -= $timezone->utc_offset;
|
||||
$offset += ($entity_send_time * 3600);
|
||||
|
||||
nlog("offset = {$offset}");
|
||||
|
||||
return $offset;
|
||||
}
|
||||
|
@ -103,6 +103,10 @@ class Company extends BaseModel
|
||||
'markdown_email_enabled',
|
||||
'stop_on_unpaid_recurring',
|
||||
'use_quote_terms_on_conversion',
|
||||
'enable_applying_payments',
|
||||
'track_inventory',
|
||||
'inventory_notification_threshold',
|
||||
'stock_notification'
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
|
@ -36,6 +36,9 @@ class Product extends BaseModel
|
||||
'tax_rate1',
|
||||
'tax_rate2',
|
||||
'tax_rate3',
|
||||
'in_stock_quantity',
|
||||
'stock_notification_threshold',
|
||||
'stock_notification',
|
||||
];
|
||||
|
||||
protected $touches = [];
|
||||
|
@ -13,6 +13,7 @@ namespace App\Services\Invoice;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasArchived;
|
||||
use App\Jobs\Entity\CreateEntityPdf;
|
||||
use App\Jobs\Inventory\AdjustProductInventory;
|
||||
use App\Jobs\Invoice\InvoiceWorkflowSettings;
|
||||
use App\Jobs\Util\UnlinkFile;
|
||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||
@ -564,6 +565,14 @@ class InvoiceService
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function adjustInventory()
|
||||
{
|
||||
if($this->invoice->company->track_inventory)
|
||||
AdjustProductInventory::dispatch($this->invoice->company, $this->invoice, null);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the invoice.
|
||||
* @return Invoice object
|
||||
|
@ -170,6 +170,10 @@ class CompanyTransformer extends EntityTransformer
|
||||
'markdown_email_enabled' => (bool) $company->markdown_email_enabled,
|
||||
'stop_on_unpaid_recurring' => (bool) $company->stop_on_unpaid_recurring,
|
||||
'use_quote_terms_on_conversion' => (bool) $company->use_quote_terms_on_conversion,
|
||||
'stock_notification' => (bool) $company->stock_notification,
|
||||
'inventory_notification_threshold' => (int) $company->inventory_notification_threshold,
|
||||
'track_inventory' => (bool) $company->track_inventory,
|
||||
'enable_applying_payments' => (bool) $company->enable_applying_payments,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,9 @@ class ProductTransformer extends EntityTransformer
|
||||
'custom_value3' => $product->custom_value3 ?: '',
|
||||
'custom_value4' => $product->custom_value4 ?: '',
|
||||
'is_deleted' => (bool) $product->is_deleted,
|
||||
'in_stock_quantity' => (int) $product->in_stock_quantity ?: 0,
|
||||
'stock_notification' => (bool) $product->stock_notification,
|
||||
'stock_notification_threshold' => (int) $product->stock_notification_threshold,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.3.94',
|
||||
'app_tag' => '5.3.94',
|
||||
'app_version' => '5.3.96',
|
||||
'app_tag' => '5.3.96',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class InventoryManagementSchema extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
|
||||
|
||||
Schema::table('companies', function (Blueprint $table) {
|
||||
$table->boolean('enable_applying_payments')->default(0);
|
||||
$table->boolean('track_inventory')->default(0);
|
||||
$table->integer('inventory_notification_threshold')->default(0);
|
||||
$table->boolean('stock_notification')->default(1);
|
||||
});
|
||||
|
||||
Schema::table('products', function (Blueprint $table){
|
||||
$table->integer('in_stock_quantity')->default(0);
|
||||
$table->boolean('stock_notification')->default(1);
|
||||
$table->integer('stock_notification_threshold')->default(0);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
48
public/flutter_service_worker.js
vendored
48
public/flutter_service_worker.js
vendored
@ -3,43 +3,43 @@ const MANIFEST = 'flutter-app-manifest';
|
||||
const TEMP = 'flutter-temp-cache';
|
||||
const CACHE_NAME = 'flutter-app-cache';
|
||||
const RESOURCES = {
|
||||
"main.dart.js": "dc33896edc7d40c104d85ca2d6c83176",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"/": "90082634bee3634faebfddf446a803a2",
|
||||
"main.dart.js": "cf8b4f4a686adceb3f1085f27a463220",
|
||||
"version.json": "3afb81924daf4f751571755436069115",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
|
||||
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
|
||||
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
|
||||
"canvaskit/canvaskit.js": "c2b4e5f3d7a3d82aed024e7249a78487",
|
||||
"flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67",
|
||||
"/": "e6fea64a985bef161e4db9ad8e7fee99",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"version.json": "3afb81924daf4f751571755436069115",
|
||||
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
||||
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
|
||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",
|
||||
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
|
||||
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
|
||||
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
|
||||
"assets/fonts/MaterialIcons-Regular.otf": "95db9098c58fd6db106f1116bae85a0b",
|
||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
|
||||
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
|
||||
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
|
||||
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
|
||||
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
|
||||
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
|
||||
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
|
||||
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
|
||||
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
|
||||
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
|
||||
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
|
||||
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
|
||||
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
|
||||
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
|
||||
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
|
||||
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
|
||||
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
|
||||
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
|
||||
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
|
||||
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
|
||||
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
|
||||
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
|
||||
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
|
||||
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
|
||||
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
|
||||
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
|
||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
"assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a",
|
||||
"assets/NOTICES": "52d7174bb068ef86545951d5bc8c5744",
|
||||
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
||||
"assets/fonts/MaterialIcons-Regular.otf": "95db9098c58fd6db106f1116bae85a0b",
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628"
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40"
|
||||
};
|
||||
|
||||
// The application shell files that are downloaded before a service worker can
|
||||
|
32992
public/main.dart.js
vendored
32992
public/main.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
32354
public/main.foss.dart.js
vendored
32354
public/main.foss.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
32676
public/main.next.dart.js
vendored
32676
public/main.next.dart.js
vendored
File diff suppressed because one or more lines are too long
310
public/main.profile.dart.js
vendored
310
public/main.profile.dart.js
vendored
File diff suppressed because one or more lines are too long
@ -117,13 +117,20 @@
|
||||
</div>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<td align="center">
|
||||
<div class="dark-bg"
|
||||
style="background-color:#f9f9f9; border: 1px solid #c2c2c2; border-bottom: none; padding-bottom: 20px; border-top-left-radius: 3px; border-top-right-radius: 3px;">
|
||||
<img class="logo-light"
|
||||
style="margin-top: 20px; max-width: 155px; display: block; margin-left: auto; margin-right: auto; "
|
||||
src="{{ $logo ?? '' }}"
|
||||
width="155" />
|
||||
|
||||
<!--[if gte mso 9]>
|
||||
<img src="{{ $logo ?? '' }}" alt="" width="155" border="0" align="middle" style="display:block;" />
|
||||
<div style="mso-hide:all;">
|
||||
<![endif]-->
|
||||
<img class="logo-light" src="{{ $logo ?? '' }}" alt="" style="margin-top: 10px; max-width: 570px; display: block; margin-left: auto; margin-right: auto;"/>
|
||||
<!--[if gte mso 9]>
|
||||
</div>
|
||||
<![endif]-->
|
||||
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -94,19 +94,24 @@
|
||||
<div style="text-align: center;margin-top: 25px; margin-bottom: 10px;"></div>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<td align="center" cellpadding="20">
|
||||
<div
|
||||
style="border: 1px solid #c2c2c2; border-bottom: none; padding-bottom: 10px; border-top-left-radius: 3px; border-top-right-radius: 3px;">
|
||||
|
||||
<img
|
||||
style="margin-top: 40px; height: 40px; display: block; margin-left: auto; margin-right: auto;"
|
||||
alt=""
|
||||
src="{{ $logo ?? '' }}"/>
|
||||
<!--[if gte mso 9]>
|
||||
<img src="{{ $logo ?? '' }}" alt="" width="400" border="0" align="middle" style="display:block;" />
|
||||
<div style="mso-hide:all;">
|
||||
<![endif]-->
|
||||
<img src="{{ $logo ?? '' }}" alt="" style="margin-top: 40px; max-width: 155px; display: block; margin-left: auto; margin-right: auto;"/>
|
||||
<!--[if gte mso 9]>
|
||||
</div>
|
||||
<![endif]-->
|
||||
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<td cellpadding="20">
|
||||
<div style="border: 1px solid #c2c2c2; border-top: none; border-bottom: none; padding: 20px; text-align: center" id="content">
|
||||
<div style="padding-top: 10px;"></div>
|
||||
|
||||
@ -120,10 +125,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td height="20">
|
||||
<div style="border: 1px solid #c2c2c2; border-top: none; border-bottom: none; padding: 20px; text-align: center" id="content"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<td cellpadding="20" bgcolor="#f9f9f9">
|
||||
<div class="dark-bg dark-text-white"
|
||||
style="text-align: center; padding-top: 10px; padding-bottom: 25px; background-color: #f9f9f9; border: 1px solid #c2c2c2; border-top: none; border-bottom-color: #f9f9f9;">
|
||||
@isset($signature)
|
||||
@ -145,7 +156,7 @@
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<td bgcolor="#242424" cellpadding="20">
|
||||
<div class="dark-bg-base"
|
||||
style="padding-top: 10px;padding-bottom: 10px; background-color: #242424; border: 1px solid #c2c2c2; border-top-color: #242424; border-bottom-color: #242424;">
|
||||
@if(isset($company))
|
||||
|
Loading…
x
Reference in New Issue
Block a user