Commit 347264c0 by 杨树贤

混合分销性质类型

parent 1db501fc
Showing with 1096 additions and 37 deletions
......@@ -89,6 +89,7 @@ class SupplierApiController extends Controller
'registered_capital',
'is_business_abnormal',
'has_legal_ID_card',
'agency_brands',
];
public function Entrance(Request $request, $id)
......
......@@ -75,7 +75,12 @@ class SupplierFilter
$query->where('is_type', $map['is_type']);
}
if ((isset($map['level']) && $map['level'] === "0") || !empty($map['level'])) {
$query->whereIn('level', explode(',', $map['level']));
$levels = explode(',', $map['level']);
if (in_array('NL', $levels)) {
$key = array_search('NL', $levels);
$levels = array_replace($levels, [$key => '']);
}
$query->whereIn('level', $levels);
}
if (isset($map['is_type']) && $map['is_type'] === "0") {
$query->where('is_type', $map['is_type']);
......
......@@ -159,6 +159,7 @@ class SupplierController extends Controller
$regionService = new RegionService();
$this->data['region_data'] = $regionService->getCityRegionData();
$this->data['brand_init_value'] = [];
$this->data['agency_brand_init_value'] = [];
//编辑
if (!empty($supplierId)) {
$this->data['title'] = '编辑供应商';
......@@ -220,6 +221,7 @@ class SupplierController extends Controller
config('field.SkipChangeSupplierTypeNames'));
$this->data['sku_upload_log_count'] = (new SkuUploadLogService())->getSkuUploadLogCount($supplierId);
$this->data['brand_init_value'] = (new StandardBrandService())->getBrandInitValue($supplier['main_brands']);
$this->data['agency_brand_init_value'] = (new StandardBrandService())->getBrandInitValue($supplier['agency_brands']);
return $this->view('编辑供应商');
}
......
......@@ -11,6 +11,7 @@ use App\Model\SupplierChannelModel;
use App\Model\SupplierExaminationModel;
use App\Utils\CsvValueBinder;
use Maatwebsite\Excel\Facades\Excel;
use Mavinoo\Batch\Batch;
class SupplierExaminationService
{
......@@ -26,13 +27,25 @@ class SupplierExaminationService
return $list;
}
//检测是否重复,目前确定唯一的维度是通过供应商名称,型号,品牌,数量,时间五个维度判断,如果一致则判断为重复数据,进行覆盖即可
public function checkExistsExamination($supplierName, $skuName, $brandName, $amount, $examineTime)
{
return SupplierExaminationModel::where('supplier_name', $supplierName)
->where('sku_name', $skuName)->where('brand_name', $brandName)->where('amount', $amount)
->where('examine_time', strtotime($examineTime))->value('id');
}
//保存
public function saveSupplierExamination($data)
{
$data = BatchTrim($data);
$data['examine_time'] = strtotime($data['examine_time']);
$data['stock_in_date'] = strtotime($data['stock_in_date']);
if (!empty($data['id'])) {
$existsExamination = $this->checkExistsExamination($data['supplier_name'], $data['sku_name'],
$data['brand_name'],
$data['amount'], $data['examine_time']);
if (!empty($data['id']) || $existsExamination) {
$data['update_time'] = time();
return SupplierExaminationModel::where('id', $data['id'])->update($data);
} else {
......@@ -69,7 +82,8 @@ class SupplierExaminationService
$channelUserNames = array_column($channelUsers, 'name');
$supplierNames = (new SupplierChannelModel())->where('is_type', 0)->pluck('supplier_name')->toArray();
//拼装数据插入校验,校验完成插入数据库
$examineData = [];
$insertData = [];
$updateData = [];
$errMsg = [];
foreach ($data as $index => $item) {
if ($this->checkArrAllNull($item)) {
......@@ -144,7 +158,7 @@ class SupplierExaminationService
$errMsg[] = "存在不合理的异常等级,等级必须为纯数字1,2,3或者不填 (第${lineNo}行)";
}
$examineData[] = [
$item = [
'order_sn' => $orderSn,
'purchase_sn' => $purchaseSn,
'examine_time' => $examineTime ? strtotime($examineTime) : 0,
......@@ -172,6 +186,14 @@ class SupplierExaminationService
'create_uid' => request()->user->userId,
'create_name' => request()->user->name,
];
//判断是否已经存在,存在的话则去批量更新
if ($id = $this->checkExistsExamination($supplierName,$skuName,$brandName,$amount,$examineTime)){
$item['id'] = $id;
$updateData[] = $item;
}else{
$insertData[] = $item;
}
}
if ($errMsg) {
......@@ -179,10 +201,19 @@ class SupplierExaminationService
throw new \Exception($errMsg);
}
$examineData = collect($examineData);
foreach ($examineData->chunk(50) as $chunk) {
if ($insertData) {
$insertData = collect($insertData);
foreach ($insertData->chunk(50) as $chunk) {
SupplierExaminationModel::insert($chunk->toArray());
}
}
if ($updateData) {
$updateData = collect($updateData);
foreach ($updateData->chunk(50) as $chunk) {
Batch::update(new SupplierExaminationModel, $chunk->toArray(), 'id');
}
}
return true;
});
return true;
......
......@@ -27,6 +27,14 @@ class SupplierAttachmentValidator
return '附件有效期为自定义的时候,时间区间必须选择';
}
$supplierGroup = SupplierChannelModel::where('supplier_id', $attachment['supplier_id'])
->value('supplier_group');
//供应商为混合分销的时候,代理证的有效期必填
if ($supplierGroup == SupplierChannelModel::SUPPLIER_GROUP_MIX && !$attachment['validity_period']) {
return '供应商为混合分销的时候,代理证的有效期必填';
}
if ($validator->fails()) {
return $validator->errors()->first();
}
......
......@@ -160,6 +160,15 @@ class SupplierValidator
//校验附件这块,新增和修改判断的逻辑不一样
if ($isAdd) {
$attachmentFields = array_unique(array_get($validateData, 'field_name', []));
$attachmentPeriods = array_unique(array_get($validateData, 'validity_period', []));
//这里的校验是当供应商性质为7(混合分销)的时候,代理证的有效期不能为空
foreach ($attachmentFields as $key => $attachmentField) {
if ($attachmentField == 'proxy_certificate' && empty($attachmentPeriods[$key])) {
$errorMessageList[] = '供应商性质为混合分销时,附件中代理证的有效期为必填,请检查对应代理证的附件有效期';
}
}
} else {
$attachmentFields = SupplierAttachmentsModel::where('supplier_id',
$supplierId)->get()->pluck('field_name')->toArray();
......@@ -194,6 +203,20 @@ class SupplierValidator
}
}
if ($validateData['supplier_group'] == SupplierChannelModel::SUPPLIER_GROUP_MIX) {
if (!in_array('proxy_certificate', $attachmentFields)) {
$errorMessageList[] = '供应商性质为混合分销,代理证必须上传';
}
if (!in_array('quality_assurance_agreement', $attachmentFields)) {
$errorMessageList[] = '供应商性质为混合分销,品质保证协议必须上传';
}
//还有代理证的有效期为必填
if (!in_array('proxy_certificate', $attachmentFields)) {
}
}
//如果选择有法人身份证,那么附件上传必须要要有法人身份证
if ($validateData['has_legal_ID_card'] == 1) {
if (!in_array('legal_ID_card', $attachmentFields)) {
......
......@@ -14,6 +14,7 @@
use App\Http\Services\DepartmentService;
use App\Http\Services\SkuService;
use Mavinoo\Batch\Batch;
Route::group(['middleware' => ['web', 'menu']], function () {
Route::get('/', 'WebController@Entrance');
......@@ -63,5 +64,5 @@ Route::group(['middleware' => ['external'], 'namespace' => 'Sync'], function ()
});
Route::match(['get', 'post'], '/test', function () {
(new \App\Http\Services\DataService())->importSupplierLevel();
});
......@@ -36,6 +36,7 @@ class SupplierChannelModel extends Model
//供应商类型
const SUPPLIER_GROUP_ORIGINAL = 1; //原厂
const SUPPLIER_GROUP_PROXY = 4; //代理
const SUPPLIER_GROUP_MIX = 7; //混合分销
//供应商地区
const REGION_CN = 2; //国内
......
......@@ -12,7 +12,8 @@
"predis/predis": "^1.1",
"vladimir-yuldashev/laravel-queue-rabbitmq": "5.2",
"maatwebsite/excel": "2.1.0",
"guzzlehttp/guzzle": "6.3"
"guzzlehttp/guzzle": "6.3",
"mavinoo/laravel-batch": "^2.3"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
......@@ -54,6 +55,7 @@
]
},
"config": {
"preferred-install": "dist"
"preferred-install": "dist",
"platform-check": false
}
}
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "5838f7b8ccfd9204e310d51188dd56a7",
"content-hash": "d2d0e5b8611ab1b35f70773d220c455b",
"packages": [
{
"name": "classpreloader/classpreloader",
......@@ -900,6 +900,68 @@
"time": "2015-12-10T18:31:14+00:00"
},
{
"name": "mavinoo/laravel-batch",
"version": "v2.3.4",
"source": {
"type": "git",
"url": "https://github.com/mavinoo/laravelBatch.git",
"reference": "126f077dec4ecabb67331694e71bf28b427daa60"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mavinoo/laravelBatch/zipball/126f077dec4ecabb67331694e71bf28b427daa60",
"reference": "126f077dec4ecabb67331694e71bf28b427daa60",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit": "^9.3@dev"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Mavinoo\\Batch\\BatchServiceProvider"
],
"aliases": {
"Batch": "Mavinoo\\Batch\\BatchFacade"
}
}
},
"autoload": {
"files": [
"src/Common/Helpers.php"
],
"psr-4": {
"Mavinoo\\Batch\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mohammad Ghanbari",
"email": "mavin.developer@gmail.com"
}
],
"description": "Insert and update batch (bulk) in laravel",
"support": {
"issues": "https://github.com/mavinoo/laravelBatch/issues",
"source": "https://github.com/mavinoo/laravelBatch/tree/v2.3.4"
},
"time": "2022-04-20T12:04:23+00:00"
},
{
"name": "monolog/monolog",
"version": "1.25.3",
"source": {
......@@ -4360,5 +4422,5 @@
"ext-curl": "*"
},
"platform-dev": [],
"plugin-api-version": "1.1.0"
"plugin-api-version": "2.1.0"
}
......@@ -156,6 +156,7 @@ return [
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
Maatwebsite\Excel\ExcelServiceProvider::class,
Mavinoo\Batch\BatchServiceProvider::class,
],
......@@ -202,7 +203,7 @@ return [
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Batch' => Mavinoo\Batch\BatchFacade::class,
],
];
......@@ -105,6 +105,7 @@ return [
'B' => 'B(优秀级)',
'C' => 'C(次优级)',
'D' => 'D(合格级)',
'NL' => '暂无等级',
],
'SupplierIsType' => [
......
......@@ -25,6 +25,7 @@ return [
4 => '原厂',
5 => '分销平台',
6 => '代工厂',
7 => '混合分销',
],
//供应商编码规则映射表,用于根据供应商类型生成编码
//比如 : 原厂=>M+7位数 代理=>D+7位数
......
......@@ -200,11 +200,15 @@
}
function addSupplier(data) {
admin.showLoading({
type: 3,
});
let url = '/api/supplier/AddSupplier?direct_apply=1';
let res = ajax(url, data.field);
admin.showLoading();
$.ajax({
url: '/api/supplier/AddSupplier?direct_apply=1',
type: 'POST',
async: true,
data: data.field,
dataType: 'json',
timeout: 20000,
success: function (res) {
if (!res) {
admin.removeLoading();
layer.msg('网络错误,请重试', {icon: 6});
......@@ -225,6 +229,13 @@
layer.msg(msg, {icon: 5})
}
}
admin.removeLoading();
},
error: function () {
admin.removeLoading();
layer.msg('网络错误', {icon: 5});
}
});
}
});
</script>
\ No newline at end of file
......@@ -126,8 +126,16 @@
}
function updateSupplier(data) {
admin.showLoading();
admin.showLoading('.layui-layer-btn0');
let res = ajax('/api/supplier/UpdateSupplier', data.field);
$.ajax({
url: '/api/supplier/UpdateSupplier',
type: 'POST',
async: true,
data: data.field,
dataType: 'json',
timeout: 20000,
success: function (res) {
if (res.err_code === 0) {
admin.putTempData("needFreshList", 1)
table.reload('receiptList')
......@@ -135,14 +143,22 @@
layer.msg(res.err_msg, {icon: 6})
} else {
let errMsg = res.err_msg;
console.log(res);
let msg = '';
$.each(errMsg.split('|'), function (index, value) {
msg += "<span>" + value + "</span><br>"
});
layer.msg(msg, {icon: 5})
}
admin.removeLoading('.layui-layer-btn0');
admin.removeLoading();
admin.showLoading('.layui-layer-btn0');
},
error: function () {
admin.removeLoading();
admin.showLoading('.layui-layer-btn0');
layer.msg('网络错误', {icon: 5});
}
});
}
});
</script>
\ No newline at end of file
......@@ -120,6 +120,9 @@
@if($supplier['region']==2)
$('.city-div').show();
@endif
@if($supplier['supplier_group']==\App\Model\SupplierChannelModel::SUPPLIER_GROUP_MIX)
$('#agency_brands_div').show();
@endif
@endif
//监听所在区域变化,中国才显示省市选择
......@@ -152,6 +155,15 @@
}
});
//监听供应商性质选择,如果为混合分销,那么要展示混合分销品牌设置
form.on('select(supplier_group)', function (data) {
if (data.value === '7') {
$('#agency_brands_div').show();
} else {
$('#agency_brands_div').hide();
}
});
//如果没有直接忽略公司校验的权限,那么就要做到下面的互相disable
@if (!checkPerm('IgnoreCompanyCheck'))
//修改供应商名称,那么公司税号就禁用,反之亦然
......@@ -191,7 +203,7 @@
});
//渲染主营品牌的多选
function getBrandOption(element, brandType) {
function getBrandOption(element, idName = 'main_brands') {
return {
el: '#' + element,
filterable: true,
......@@ -206,8 +218,8 @@
},
remoteSearch: true,
pageRemote: true,
template({ item, sels, name, value }){
return item.brand_name + '<span style="position: absolute; right: 10px; color: #8799a3">'+ item.mapping_brand_names +'</span>'
template({item, sels, name, value}) {
return item.brand_name + '<span style="position: absolute; right: 10px; color: #8799a3">' + item.mapping_brand_names + '</span>'
},
filterMethod: function (val, item, index, prop) {
},
......@@ -243,19 +255,25 @@
for (let i in arr) {
brandIds += arr[i].brand_id + ',';
}
let idName = 'main_brands';
$('#' + idName).val(brandIds);
},
};
}
let brandOption = getBrandOption('brand_selector', 2);
//主营品牌的渲染
let brandOption = getBrandOption('brand_selector');
let brandSelector = xmSelect.render(brandOption);
let brandIds = $('#main_brands').attr('value');
let brandInitValue = {!! json_encode($brand_init_value?:[])!!};
console.log(brandInitValue);
brandSelector.setValue(brandInitValue);
//代理品牌的渲染
let agencyBrandOption = getBrandOption('agency_brand_selector', 'agency_brands');
let agencyBrandSelector = xmSelect.render(agencyBrandOption);
let agencyBrandIds = $('#agency_brands').attr('value');
let agencyBrandInitValue = {!! json_encode($agency_brand_init_value?:[])!!};
agencyBrandSelector.setValue(agencyBrandInitValue);
//供应商标签的多选
function getTagOption(element) {
//获取系统标签列表
......
......@@ -91,7 +91,8 @@
<label class="layui-form-label">注册公司名 : </label>
<div class="layui-input-block">
<input type="text" name="register_company_name" id="register_company_name"
placeholder="请输入注册公司名,注册公司名必须同执照" class="layui-input" value="{{$supplier['register_company_name']}}">
placeholder="请输入注册公司名,注册公司名必须同执照" class="layui-input"
value="{{$supplier['register_company_name']}}">
</div>
</div>
<div class="layui-col-md5">
......@@ -222,6 +223,23 @@
id="main_brands">
</div>
</div>
{{--选择“混合分销”时,在主营品牌下面新增一栏“代理品牌”;代理品牌取值同主营品牌一样--}}
<div class="layui-form-item" id="agency_brands_div"
style="
@if(!empty($supplier)&&$supplier['supplier_group']!=\App\Model\SupplierChannelModel::SUPPLIER_GROUP_MIX)
display:none;
@endif
">
<label class="layui-form-label">
<span class="require">*</span>
代理品牌</label>
<div class="layui-input-block" style="margin-top: 15px">
<div id="agency_brand_selector" class="layui-input-inline" style="width: 100%;">
</div>
<input type="hidden" name="agency_brands" value="{{$supplier['agency_brands'] or ''}}"
id="agency_brands">
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label"><span class="require">*</span>合作类型</label>
......
......@@ -37,26 +37,80 @@ namespace Composer\Autoload;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
......@@ -66,28 +120,47 @@ class ClassLoader
return array();
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return string[] Array of classname => path
* @psalm-var array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
public function addClassMap(array $classMap)
{
......@@ -103,8 +176,10 @@ class ClassLoader
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
......@@ -148,10 +223,12 @@ class ClassLoader
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
......@@ -196,7 +273,9 @@ class ClassLoader
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
......@@ -212,9 +291,11 @@ class ClassLoader
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
......@@ -234,6 +315,8 @@ class ClassLoader
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
......@@ -256,6 +339,8 @@ class ClassLoader
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
......@@ -276,6 +361,8 @@ class ClassLoader
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
......@@ -296,25 +383,44 @@ class ClassLoader
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
......@@ -323,6 +429,8 @@ class ClassLoader
return true;
}
return null;
}
/**
......@@ -367,6 +475,21 @@ class ClassLoader
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
......@@ -438,6 +561,10 @@ class ClassLoader
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
......
......@@ -20,5 +20,6 @@ return array(
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'f0906e6318348a765ffb6eb24e0d0938' => $vendorDir . '/laravel/framework/src/Illuminate/Foundation/helpers.php',
'58571171fd5812e6e447dce228f52f4d' => $vendorDir . '/laravel/framework/src/Illuminate/Support/helpers.php',
'880d9aa7c2c689853e94e8a3794c8282' => $vendorDir . '/mavinoo/laravel-batch/src/Common/Helpers.php',
'cdab8ec77ae0402ce2cb2fdd82a8a401' => $baseDir . '/app/Http/function.php',
);
......@@ -36,6 +36,7 @@ return array(
'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'),
'PhpAmqpLib\\' => array($vendorDir . '/php-amqplib/php-amqplib/PhpAmqpLib'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Mavinoo\\Batch\\' => array($vendorDir . '/mavinoo/laravel-batch/src'),
'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'),
'JakubOnderka\\PhpConsoleColor\\' => array($vendorDir . '/jakub-onderka/php-console-color/src'),
'Illuminate\\' => array($vendorDir . '/laravel/framework/src/Illuminate'),
......
......@@ -23,12 +23,12 @@ class ComposerAutoloaderInit2a46e5674e69fd121680370ab820bf2e
}
spl_autoload_register(array('ComposerAutoloaderInit2a46e5674e69fd121680370ab820bf2e', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit2a46e5674e69fd121680370ab820bf2e', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit2a46e5674e69fd121680370ab820bf2e::getInitializer($loader));
} else {
......
.idea
vendor
composer.lock
.php_cs.cache
\ No newline at end of file
MIT License
Copyright (c) 2017 Mohammad Ghanbari
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Laravel BATCH (BULK)
Insert and update batch (bulk) in laravel
[![License](https://poser.pugx.org/mavinoo/laravel-batch/license)](https://packagist.org/packages/mavinoo/laravel-batch)
[![Latest Stable Version](https://poser.pugx.org/mavinoo/laravel-batch/v/stable)](https://packagist.org/packages/mavinoo/laravel-batch)
[![Total Downloads](https://poser.pugx.org/mavinoo/laravel-batch/downloads)](https://packagist.org/packages/mavinoo/laravel-batch)
[![Daily Downloads](https://poser.pugx.org/mavinoo/laravel-batch/d/daily)](https://packagist.org/packages/mavinoo/laravel-batch)
# Install
`composer require mavinoo/laravel-batch`
# Service Provider
file app.php in array providers :
`Mavinoo\Batch\BatchServiceProvider::class,`
# Aliases
file app.php in array aliases :
`'Batch' => Mavinoo\Batch\BatchFacade::class,`
# Example Update 1
```php
use App\Models\User;
$userInstance = new User;
$value = [
[
'id' => 1,
'status' => 'active',
'nickname' => 'Mohammad'
] ,
[
'id' => 5,
'status' => 'deactive',
'nickname' => 'Ghanbari'
] ,
];
$index = 'id';
Batch::update($userInstance, $value, $index);
```
# Example Update 2
```php
use App\Models\User;
$userInstance = new User;
$value = [
[
'id' => 1,
'status' => 'active'
],
[
'id' => 5,
'status' => 'deactive',
'nickname' => 'Ghanbari'
],
[
'id' => 10,
'status' => 'active',
'date' => Carbon::now()
],
[
'id' => 11,
'username' => 'mavinoo'
]
];
$index = 'id';
Batch::update($userInstance, $value, $index);
```
# Example Increment / Decrement
```php
use App\Models\User;
$userInstance = new User;
$value = [
[
'id' => 1,
'balance' => ['+', 500] // Add
] ,
[
'id' => 2,
'balance' => ['-', 200] // Subtract
] ,
[
'id' => 3,
'balance' => ['*', 5] // Multiply
] ,
[
'id' => 4,
'balance' => ['/', 2] // Divide
] ,
[
'id' => 5,
'balance' => ['%', 2] // Modulo
] ,
];
$index = 'id';
Batch::update($userInstance, $value, $index);
```
# Example Insert
```php
use App\Models\User;
$userInstance = new User;
$columns = [
'firstName',
'lastName',
'email',
'isActive',
'status',
];
$values = [
[
'Mohammad',
'Ghanbari',
'emailSample_1@gmail.com',
'1',
'0',
] ,
[
'Saeed',
'Mohammadi',
'emailSample_2@gmail.com',
'1',
'0',
] ,
[
'Avin',
'Ghanbari',
'emailSample_3@gmail.com',
'1',
'0',
] ,
];
$batchSize = 500; // insert 500 (default), 100 minimum rows in one query
$result = Batch::insert($userInstance, $columns, $values, $batchSize);
```
```php
// result : false or array
sample array result:
Array
(
[totalRows] => 384
[totalBatch] => 500
[totalQuery] => 1
)
```
# Helper batch()
```php
// ex: update
$result = batch()->update($userInstance, $value, $index);
// ex: insert
$result = batch()->insert($userInstance, $columns, $values, $batchSize);
```
# Tests
If you don't have phpunit installed on your project, first run `composer require phpunit/phpunit`
In the root of your laravel app, run `./vendor/bin/phpunit ./vendor/mavinoo/laravel-batch/tests`
# Donate
BTC Address: 16XDxkcqiEJ8DYf4xWxu7WK3Peo29TvXxD
{
"name": "mavinoo/laravel-batch",
"description": "Insert and update batch (bulk) in laravel",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Mohammad Ghanbari",
"email": "mavin.developer@gmail.com"
}
],
"require": {
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit": "^9.3@dev"
},
"autoload": {
"psr-4": {
"Mavinoo\\Batch\\": "src/"
},
"files": [
"src/Common/Helpers.php"
]
},
"extra": {
"laravel": {
"providers": [
"Mavinoo\\Batch\\BatchServiceProvider"
],
"aliases": {
"Batch": "Mavinoo\\Batch\\BatchFacade"
}
}
},
"minimum-stability": "dev"
}
<?php declare(strict_types=1);
namespace Mavinoo\Batch;
use Illuminate\Support\Facades\Facade;
class BatchFacade extends Facade
{
/**
* Get facade accessor to retrieve instance.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'Batch';
}
}
<?php declare(strict_types=1);
namespace Mavinoo\Batch;
use Illuminate\Database\Eloquent\Model;
interface BatchInterface
{
/**
* Update multiple rows.
*
* @param Model $table
* @param array $values
* @param string|null $index
* @param bool $raw
* @return mixed
*/
public function update(Model $table, array $values, string $index = null, bool $raw = false);
/**
* Update multiple rows with two index.
*
* @param Model $table
* @param array $values
* @param string|null $index
* @param string|null $index2
* @param bool $raw
* @return mixed
*/
public function updateWithTwoIndex(Model $table, array $values, string $index = null, string $index2 = null, bool $raw = false);
/**
* Insert multiple rows.
*
* @param Model $table
* @param array $columns
* @param array $values
* @param int $batchSize
* @param bool $insertIgnore
* @return mixed
*/
public function insert(Model $table, array $columns, array $values, int $batchSize = 500, bool $insertIgnore = false);
}
<?php declare(strict_types=1);
namespace Mavinoo\Batch;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\DatabaseManager;
class BatchServiceProvider extends ServiceProvider
{
/**
* Register Batch instance to IOC.
*
* @updateedBy Ibrahim Sakr <ebrahimes@gmail.com>
*/
public function register()
{
$this->app->bind('Batch', function ($app) {
return new Batch($app->make(DatabaseManager::class));
});
}
}
<?php declare(strict_types=1);
namespace Mavinoo\Batch\Common;
class Common
{
/**
* Escape values according to mysql.
*
* @param $fieldValue
* @return array|string|string[]
*/
public static function mysql_escape($fieldValue)
{
if (is_array($fieldValue)) {
return array_map(__METHOD__, $fieldValue);
}
if (is_bool($fieldValue)) {
return (int)$fieldValue;
}
if (self::is_json($fieldValue)) {
return self::safeJson($fieldValue);
}
if (!empty($fieldValue) && is_string($fieldValue)) {
return str_replace(
['\\', "\0", "\n", "\r", "'", '"', "\x1a"],
['\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'],
$fieldValue
);
}
return $fieldValue;
}
/**
* Disable Backtick.
*
* @param $drive
* @return boolean
*/
public static function disableBacktick($drive)
{
return in_array($drive, ['pgsql', 'sqlsrv']);
}
protected static function safeJsonString($fieldValue)
{
return str_replace(
["'"],
["''"],
$fieldValue
);
}
protected static function is_json($str): bool
{
if (!is_string($str) || is_numeric($str)) {
return false;
}
$json = json_decode($str);
return $json && $str != $json;
}
protected static function safeJson($jsonData, $asArray = false)
{
$jsonData = json_decode($jsonData, true);
$safeJsonData = [];
if (!is_array($jsonData)) {
return $jsonData;
}
foreach ($jsonData as $key => $value) {
if (self::is_json($value)) {
$safeJsonData[$key] = self::safeJson($value, true);
} elseif (is_string($value)) {
$safeJsonData[$key] = self::safeJsonString($value);
} elseif (is_array($value)) {
$safeJsonData[$key] = self::safeJson(json_encode($value), true);
} else {
$safeJsonData[$key] = $value;
}
}
return $asArray ? $safeJsonData : json_encode($safeJsonData, JSON_UNESCAPED_UNICODE);
}
}
<?php declare(strict_types=1);
if (!function_exists('batch')) {
/**
* Batch helper to get Mavino\Batch\Batch instance.
*
* @return mixed
*/
function batch()
{
return app('Mavinoo\Batch\Batch');
}
}
<?php declare(strict_types=1);
use Mavinoo\Batch\Batch;
require_once 'BootstrapDatabase.php';
class BatchInsertTest extends BootstrapDatabase
{
public $columns = [
'email',
'password',
'name',
'status',
'is_vip'
];
public function testBatchInsertWithFacade()
{
$values = [
[
'djunehor@gmail.com',
bcrypt('djunehor'),
'djunehor',
'active',
true,
],
[
'samuel@gmail.com',
bcrypt('samuel'),
'samuel',
'whodey',
false,
],
[
'general@gmail.com',
bcrypt('general'),
'general',
'inactive',
false,
]
];
$batchSize = 500; // insert 500 (default), 100 minimum rows in one query
$result = Batch::insert($this->model, $this->columns, $values, $batchSize);
$this->assertIsArray($result);
$this->assertTrue($result['totalRows'] === 3);
$this->assertTrue($result['totalBatch'] === 500);
$this->model->truncate();
}
public function testBatchInsertIncorrectColumnCount()
{
$columns = [
'email',
'password',
'name',
'status',
];
$values = [
[
'djunehor@gmail.com',
bcrypt('djunehor'),
'djunehor',
'active',
],
[
'samuel@gmail.com',
bcrypt('samuel'),
'samuel',
'whodey',
],
[
'general@gmail.com',
bcrypt('general'),
'general',
'inactive',
]
];
$batchSize = 500; // insert 500 (default), 100 minimum rows in one query
$result = Batch::insert($this->model, $this->columns, $values, $batchSize);
$this->assertFalse($result);
}
public function testBatchInsertWithHelper()
{
$values = [
[
'djunehor@gmail.com',
bcrypt('djunehor'),
'djunehor',
'active',
true,
],
[
'samuel@gmail.com',
bcrypt('samuel'),
'samuel',
'whodey',
false,
],
[
'general@gmail.com',
bcrypt('general'),
'general',
'inactive',
false,
]
];
$batchSize = 500; // insert 500 (default), 100 minimum rows in one query
$result = batch()->insert($this->model, $this->columns, $values, $batchSize);
$this->assertIsArray($result);
$this->assertTrue($result['totalRows'] === 3);
$this->assertTrue($result['totalBatch'] === 500);
$this->model->truncate();
}
}
<?php declare(strict_types=1);
require_once 'BootstrapDatabase.php';
use Carbon\Carbon;
use Mavinoo\Batch\Batch;
class BatchUpdateTest extends BootstrapDatabase
{
public $columns = [
'email',
'password',
'name',
'status',
'is_vip',
];
private function insert()
{
$values = [
[
'djunehor@gmail.com',
bcrypt('djunehor'),
'djunehor',
'active',
true,
],
[
'samuel@gmail.com',
bcrypt('samuel'),
'samuel',
'whodey',
false,
],
[
'general@gmail.com',
bcrypt('general'),
'general',
'inactive',
false,
]
];
$batchSize = 500; // insert 500 (default), 100 minimum rows in one query
$result = Batch::insert($this->model, $this->columns, $values, $batchSize);
$this->assertIsArray($result);
$this->assertTrue($result['totalRows'] === 3);
$this->assertTrue($result['totalBatch'] === 500);
}
public function testBatchUpdateWithFacade()
{
$this->insert();
$columnValues = [
[
'id' => 1,
'name' => 'amala',
'is_vip' => false
],
[
'id' => 2,
'status' => 'deactive',
'name' => 'Ghanbari'
],
[
'id' => 3,
'status' => 'active',
'created_at' => Carbon::now()
]
];
$index = 'id';
$result = Batch::update($this->model, $columnValues, $index);
$member = $this->model->findOrFail(1);
$this->assertTrue($result === 3);
$this->assertEquals('amala', $member->name);
$this->assertFalse($member->is_vip);
$this->model->truncate();
}
public function testBatchUpdateWithHelper()
{
$this->insert();
$columnValues = [
[
'id' => 1,
'name' => 'amala',
'is_vip' => false
],
[
'id' => 2,
'status' => 'deactive',
'name' => 'Ghanbari'
],
[
'id' => 3,
'status' => 'active',
'created_at' => Carbon::now()
]
];
$index = 'id';
$result = batch()->update($this->model, $columnValues, $index);
$member = $this->model->findOrFail(1);
$this->assertTrue($result === 3);
$this->assertEquals('amala', $member->name);
$this->assertFalse($member->is_vip);
$this->model->truncate();
}
}
<?php declare(strict_types=1);
require_once 'TestModel.php';
use Tests\TestCase;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
class BootstrapDatabase extends TestCase
{
public $model;
public function setUp(): void
{
parent::setUp();
$tableName = (new TestModel())->tableName();
if (! Schema::hasTable($tableName)) {
Schema::create($tableName, function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->string('email')->unique();
$table->string('password');
$table->string('status')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
$this->model = new TestModel();
$this->model->truncate();
}
public function tearDown(): void
{
Schema::dropIfExists((new TestModel())->tableName());
}
}
<?php declare(strict_types=1);
class TestModel extends \Illuminate\Database\Eloquent\Model
{
protected $table = 'HmKTjCJgLN9bBq7KXzI3';
protected $casts = [
'is_vip' => 'boolean'
];
/**
* Get name of the table.
*
* @return string
*/
public function tableName()
{
return $this->table;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment