This commit is contained in:
wanghai
2026-06-12 19:55:13 +08:00
parent 1895a0fbd9
commit ffeaa23f01
34 changed files with 1089 additions and 354 deletions

View File

@@ -795,8 +795,6 @@ class Distributor extends BaseController
$filter = [];
// $filter['is_valid'] = 'true';
$type = $request->input('type', 0); // 过滤条件
$noHaving = false; // 是否过滤离用户的经纬度比较远的店铺 【true 不过滤】【false 过滤】
switch ($type) {
@@ -927,11 +925,11 @@ class Distributor extends BaseController
// 默认拿不是总店的店铺
$filter['distributor_self'] = 0;
// $filter['is_valid'] = 'true';
// 默认只返回启用的店铺,可通过 is_valid 参数显式筛选
if ($request->input('is_valid')) {
$filter['is_valid'] = $request->input('is_valid');
} else {
$filter['is_valid'] = ['true', 'false'];
$filter['is_valid'] = 'true';
}
if ($request->input('get_shop')) {

View File

@@ -21,7 +21,7 @@ class StoreHomePage extends BaseController
* path="/wxapp/employeepurchase/store-home-page/{id}",
* summary="内购模版详情(含完整模板装修数据)",
* tags={"内购"},
* description="返回内购模版表字段、pages_template 列表完整行pages_template_record、以及与 pagestemplate/detail 同构的 page_template_detaillist/config/tab_bar 等)。当存在 weapp_customize_page_id 时page_template_detail 优先从 wechat_weapp_setting 的 page_name=custom_{weapp_customize_page_id}version=v1.0.1 读取(与后台 shopDecoration 保存一致);若无匹配行则回退为商城首页 indexv1.0.2。resolved_pages_template_id 为装修 pages_template 主键,与自定义页 page_name 语义不同。需传 distributor_id。可选 e_activity_id 参与组件价活动上下文。",
* description="返回内购模版表字段、pages_template 列表完整行pages_template_record、以及与 pagestemplate/detail 同构的 page_template_detaillist/config/tab_bar 等)。当存在 weapp_customize_page_id 时page_template_detail 从 wechat_weapp_setting 的 page_name=custom_{weapp_customize_page_id} 读取,version 依次尝试 shop_{distributor_id} 与 v1.0.1。resolved_pages_template_id 为装修 pages_template 主键,与自定义页 page_name 语义不同。可选 distributor_ide_activity_id。",
* operationId="employeepurchaseStoreHomePageDetailFront",
* @SWG\Parameter(name="Authorization", in="header", description="JWT验证token", required=true, type="string"),
* @SWG\Parameter(name="id", in="path", description="内购模版主键 employee_purchase_store_home_page.id", required=true, type="integer"),

View File

@@ -63,6 +63,66 @@ class StoreHomePageService
return 'custom_'.$weappCustomizePageId;
}
/**
* 自定义页装修 version 候选(按优先级)。
* - decorate/index scene=1010门店维度写入 shop_{distributor_id}
* - 旧 shopDecoration page_template固定 v1.0.1(与 distributor 无关)
*
* @return list<string>
*/
public static function customDecorationSettingVersionCandidates(int $rowDistributorId, int $authDistributorId): array
{
$distributorId = $rowDistributorId > 0 ? $rowDistributorId : $authDistributorId;
$versions = [];
if ($distributorId > 0) {
$versions[] = 'shop_'.$distributorId;
}
$versions[] = self::CUSTOM_DECORATION_SETTING_VERSION;
return array_values(array_unique($versions));
}
/**
* 拉取 wechat_weapp_setting 时尝试的 template_namedecorate/index scene=1010 曾硬编码 yykweishop
*
* @param array<string,mixed> $storeHomeRow
*
* @return list<string>
*/
public static function decorationTemplateNameCandidates(array $storeHomeRow): array
{
$names = [];
$primary = (string) ($storeHomeRow['template_name'] ?? '');
if ($primary !== '') {
$names[] = $primary;
}
if ($primary !== 'yykweishop') {
$names[] = 'yykweishop';
}
return array_values(array_unique($names));
}
/**
* 解析 pages_template 列表时的查询计划(按优先级)。
*
* @return list<array{distributor_id: int, weapp_pages: string}>
*/
public static function pagesTemplateListSearchPlans(int $rowDistributorId): array
{
if ($rowDistributorId > 0) {
return [
['distributor_id' => $rowDistributorId, 'weapp_pages' => 'distributor_index'],
['distributor_id' => $rowDistributorId, 'weapp_pages' => 'index'],
['distributor_id' => 0, 'weapp_pages' => 'index'],
];
}
return [
['distributor_id' => 0, 'weapp_pages' => 'index'],
];
}
/**
* @param array<string,mixed>|null $detail PagesTemplateServices::content 返回值
*/
@@ -253,10 +313,11 @@ class StoreHomePageService
'page_template_detail' => null,
];
$templateName = (string) ($row['template_name'] ?? '');
$pid = (int) ($resolved['resolved_pages_template_id'] ?? 0);
if ($pid > 0) {
$distId = (int) ($row['distributor_id'] ?? 0);
$customizeId = isset($row['weapp_customize_page_id']) ? (int) $row['weapp_customize_page_id'] : 0;
$distId = (int) ($row['distributor_id'] ?? 0);
$customizeId = isset($row['weapp_customize_page_id']) ? (int) $row['weapp_customize_page_id'] : 0;
if ($templateName !== '' && ($pid > 0 || $customizeId > 0)) {
$pagesTemplateServices = new PagesTemplateServices();
$indexParams = [
@@ -264,8 +325,8 @@ class StoreHomePageService
'regionauth_id' => 0,
'user_id' => $userId,
'distributor_id' => $distId,
'weapp_pages' => 'index',
'template_name' => (string) ($row['template_name'] ?? ''),
'weapp_pages' => $distId > 0 ? 'distributor_index' : 'index',
'template_name' => $templateName,
'version' => self::INDEX_DECORATION_SETTING_VERSION,
'page' => '1',
'page_size' => '50',
@@ -277,26 +338,14 @@ class StoreHomePageService
$customPageName = self::weappSettingPageNameForCustomizePage($customizeId);
if ($customPageName !== null) {
$customParams = array_merge($indexParams, [
'version' => self::CUSTOM_DECORATION_SETTING_VERSION,
'weapp_setting_page_name' => $customPageName,
]);
$detail = $pagesTemplateServices->content($customParams);
if (!self::pageTemplateDetailHasNonEmptyList($detail)) {
$customParams['weapp_setting_pages_template_id'] = 0;
$detail = $pagesTemplateServices->content($customParams);
}
if (!self::pageTemplateDetailHasNonEmptyList($detail)) {
app('log')->warning('[StoreHomePageService] enterprise_store_home 自定义页装修无匹配 wechat_weapp_setting回退 index', [
'company_id' => $companyId,
'store_home_page_id' => $id,
'weapp_customize_page_id' => $customizeId,
'weapp_setting_page_name' => $customPageName,
]);
$detail = $pagesTemplateServices->content($indexParams);
}
$base['page_template_detail'] = $detail;
} else {
$base['page_template_detail'] = $this->fetchCustomPageDecorationDetail(
$companyId,
$row,
$customPageName,
$distId,
$authDistributorId
);
} elseif ($pid > 0) {
$base['page_template_detail'] = $pagesTemplateServices->content($indexParams);
}
}
@@ -325,19 +374,25 @@ class StoreHomePageService
}
$distributorId = (int) ($storeHomeRow['distributor_id'] ?? 0);
$weappPages = $distributorId > 0 ? 'distributor_index' : 'index';
$pagesTemplateServices = new PagesTemplateServices();
$listResult = $pagesTemplateServices->lists([
'company_id' => $companyId,
'distributor_id' => $distributorId,
'weapp_pages' => $weappPages,
'page_no' => 1,
'page_size' => 100,
]);
$rows = $listResult['list'] ?? [];
$picked = self::pickResolvedPagesTemplateRow(is_array($rows) ? $rows : [], $templateName);
$picked = null;
foreach (self::decorationTemplateNameCandidates($storeHomeRow) as $tryTemplateName) {
foreach (self::pagesTemplateListSearchPlans($distributorId) as $plan) {
$listResult = $pagesTemplateServices->lists([
'company_id' => $companyId,
'distributor_id' => $plan['distributor_id'],
'weapp_pages' => $plan['weapp_pages'],
'page_no' => 1,
'page_size' => 100,
]);
$rows = $listResult['list'] ?? [];
$picked = self::pickResolvedPagesTemplateRow(is_array($rows) ? $rows : [], $tryTemplateName);
if ($picked !== null) {
break 2;
}
}
}
if ($picked === null) {
return [
@@ -361,6 +416,122 @@ class StoreHomePageService
];
}
/**
* 自定义页装修:与后台 getParamByTempName 一致custom_{id} + shop_{distributor_id}pages_template_id=0
*
* @param array<string,mixed> $storeHomeRow
*
* @return array{list: array<int, array<string,mixed>>, config: array<int, array<string,mixed>>}
*/
private function fetchCustomPageDecorationDetail(
int $companyId,
array $storeHomeRow,
string $customPageName,
int $distId,
int $authDistributorId
): array {
foreach (self::decorationTemplateNameCandidates($storeHomeRow) as $tryTemplateName) {
foreach (self::customDecorationSettingVersionCandidates($distId, $authDistributorId) as $version) {
$entities = $this->weappSettingRepository->getParamByTempName(
$companyId,
$tryTemplateName,
$customPageName,
null,
$version,
0
);
$list = self::buildTemplateConfListFromWeappSettingEntities($entities, $companyId, $tryTemplateName);
if ($list !== []) {
return self::buildPageTemplateDetailFromTemplateConfList($list);
}
}
}
return ['list' => [], 'config' => []];
}
/**
* @param mixed $raw
*
* @return array<string,mixed>
*/
public static function safeDecodeWeappSettingParams($raw): array
{
if (is_array($raw)) {
return $raw;
}
if (!is_string($raw) || $raw === '') {
return [];
}
$unserialized = @unserialize($raw);
if (is_array($unserialized)) {
return $unserialized;
}
$decoded = json_decode($raw, true);
return is_array($decoded) ? $decoded : [];
}
/**
* @param mixed $entities
*
* @return array<int,array<string,mixed>>
*/
public static function buildTemplateConfListFromWeappSettingEntities($entities, int $companyId, string $fallbackTemplateName = ''): array
{
if ($entities instanceof \Traversable) {
$entities = iterator_to_array($entities);
}
if (!is_array($entities)) {
return [];
}
$list = [];
foreach ($entities as $row) {
if (!is_object($row)) {
continue;
}
$pageName = method_exists($row, 'getPageName') ? (string) $row->getPageName() : '';
$list[] = [
'id' => method_exists($row, 'getId') ? $row->getId() : 0,
'template_name' => method_exists($row, 'getTemplateName') ? $row->getTemplateName() : $fallbackTemplateName,
'company_id' => method_exists($row, 'getCompanyId') ? $row->getCompanyId() : $companyId,
'name' => method_exists($row, 'getName') ? (string) $row->getName() : '',
'page_name' => $pageName !== '' ? $pageName : 'index',
'params' => self::safeDecodeWeappSettingParams(method_exists($row, 'getParams') ? $row->getParams() : null),
];
}
return $list;
}
/**
* @param array<int,array<string,mixed>> $list
*
* @return array<string,mixed>
*/
public static function buildPageTemplateDetailFromTemplateConfList(array $list): array
{
$config = [];
foreach ($list as $row) {
if (!is_array($row)) {
continue;
}
$params = $row['params'] ?? null;
if (is_array($params) && isset($params['name']) && isset($params['base'])) {
$config[] = $params;
}
}
return [
'list' => $list,
'config' => $config,
];
}
/**
* 从 pages_template 列表中选出与内购模版 template_name 一致且启用的记录;多条时取列表顺序第一条。
*

View File

@@ -18,6 +18,7 @@
namespace GoodsBundle\Http\FrontApi\V1\Action;
use App\Http\Controllers\Controller as BaseController;
use CompanysBundle\Ego\CompanysActivationEgo;
use DistributionBundle\Services\DistributorService;
use GoodsBundle\Services\ItemsCategoryService;
use GoodsBundle\Services\ItemsRelCatsService;
@@ -138,8 +139,13 @@ class Category extends BaseController
// 小程序端仅返回前台展示的分类
$filter['is_show_front'] = 1;
if ($request->input('distributor_id')) {
// $filter['distributor_id'] = $request->input('distributor_id');
$distributorId = (int)$request->input('distributor_id', 0);
$company = (new CompanysActivationEgo())->check($company_id);
$productModel = $company['product_model'] ?? 'platform';
$itemsCategoryService = new ItemsCategoryService();
$categoryDistributorId = $itemsCategoryService->resolveCategoryDistributorIdForFront($productModel, $distributorId);
if ($productModel !== 'standard' && $categoryDistributorId > 0) {
$filter['distributor_id'] = $categoryDistributorId;
}
$onlyTop = $request->input('only_top', false);
@@ -148,7 +154,6 @@ class Category extends BaseController
$filter['category_level'] = 1;
}
$itemsCategoryService = new ItemsCategoryService();
$result = $itemsCategoryService->getItemsCategory($filter, true, 1, -1, ['sort' => 'DESC', 'created' => 'ASC'], 'category_id,category_name,category_level,parent_id,image_url,customize_page_id');
// 分类获取不到获取商城主类目
@@ -180,8 +185,9 @@ class Category extends BaseController
}
}
$distributorId = (int)$request->input('distributor_id', 0);
if ($distributorId > 0 && $itemsCategoryService->isSaleableCategoryFilterEnabled($company_id)) {
$applySaleableFilter = $itemsCategoryService->shouldApplySaleableFilterForFront($productModel, $distributorId)
|| ($distributorId > 0 && $itemsCategoryService->isSaleableCategoryFilterEnabled($company_id));
if ($distributorId > 0 && $applySaleableFilter) {
$result = $itemsCategoryService->filterCategoryTreeBySaleableItems($company_id, $distributorId, $result);
}
@@ -444,13 +450,26 @@ class Category extends BaseController
$filter['company_id'] = $company_id;
if ($request->input('distributor_id')) {
$filter['distributor_id'] = $request->input('distributor_id');
$distributorId = (int)$request->input('distributor_id', 0);
$company = (new CompanysActivationEgo())->check($company_id);
$productModel = $company['product_model'] ?? 'platform';
$itemsCategoryService = new ItemsCategoryService();
$categoryDistributorId = $itemsCategoryService->resolveCategoryDistributorIdForFront($productModel, $distributorId);
if ($productModel !== 'standard' && $categoryDistributorId > 0) {
$filter['distributor_id'] = $categoryDistributorId;
}
$filter['is_main_category'] = $request->input('is_main_category', false);
// $filter['category_level'] = $request->input('category_level');
if ($itemsCategoryService->shouldApplySaleableFilterForFront($productModel, $distributorId)) {
$filter['category_id'] = $itemsCategoryService->getSaleableTopLevelCategoryIds($company_id, $distributorId);
if (empty($filter['category_id'])) {
return $this->response->array(['list' => [], 'total_count' => 0]);
}
$result = $itemsCategoryService->lists($filter);
return $this->response->array($result);
}
$settingService = new SettingService();
$config = $settingService->getConfig($company_id);
@@ -463,14 +482,18 @@ class Category extends BaseController
$itemFilter['item_type'] = 'normal';
$itemFilter['is_default'] = true;
$distributorFilter = [
'company_id' => $company_id,
'is_valid' => 'true'
];
$distributorService = new DistributorService();
$validDistributorList = $distributorService->getDistributorOriginalList($distributorFilter, 1, -1);
$validDistributorIds = array_column($validDistributorList['list'], 'distributor_id');
$itemFilter['distributor_id'] = array_merge(['0'], $validDistributorIds);
if ($categoryDistributorId > 0) {
$itemFilter['distributor_id'] = $categoryDistributorId;
} else {
$distributorFilter = [
'company_id' => $company_id,
'is_valid' => 'true'
];
$distributorService = new DistributorService();
$validDistributorList = $distributorService->getDistributorOriginalList($distributorFilter, 1, -1);
$validDistributorIds = array_column($validDistributorList['list'], 'distributor_id');
$itemFilter['distributor_id'] = array_merge(['0'], $validDistributorIds);
}
$itemsService = new ItemsService();
$itemsList = $itemsService->itemsRepository->list($itemFilter, [], -1, 1, ['item_id']);
@@ -480,7 +503,6 @@ class Category extends BaseController
$itemsRelCatsService = new ItemsRelCatsService();
$itemsRelCatsList = $itemsRelCatsService->lists($itemRelCatsParams);
$itemsCategoryService = new ItemsCategoryService();
$filter['category_id'] = [];
foreach ($itemsRelCatsList['list'] as $cat) {
$category = $itemsCategoryService->getInfo(['company_id' => $company_id, 'category_id' => $cat['category_id']]);
@@ -495,7 +517,6 @@ class Category extends BaseController
}
}
$itemsCategoryService = new ItemsCategoryService();
$result = $itemsCategoryService->lists($filter);
return $this->response->array($result);

View File

@@ -1498,4 +1498,54 @@ class Items extends BaseController
unset($itemInfo['itemId'], $itemInfo['consumeType'], $itemInfo['itemName'], $itemInfo['itemBn'], $itemInfo['companyId'], $itemInfo['item_main_cat_id'], $itemInfo['nospec'], $itemInfo['pics_create_qrcode']);
return $this->response->array($itemInfo);
}
/**
* @SWG\Get(
* path="/wxapp/goods/items/batch",
* summary="批量获取商品基本信息",
* tags={"商品"},
* description="批量获取商品基本信息图片、ID、名称、价格供 ecshopx-web 等端使用",
* operationId="getBatchItems",
* @SWG\Parameter( name="Authorization", in="header", description="JWT验证token", type="string" ),
* @SWG\Parameter( name="item_ids", in="query", description="商品ID列表逗号分隔如 1,2,3", required=true, type="string" ),
* @SWG\Response(
* response=200,
* description="成功返回结构",
* @SWG\Schema(
* @SWG\Property(
* property="data",
* type="array",
* @SWG\Items(
* type="object",
* @SWG\Property(property="item_id", type="integer", description="商品ID"),
* @SWG\Property(property="item_name", type="string", description="商品名称"),
* @SWG\Property(property="price", type="integer", description="销售价(单位:分)"),
* @SWG\Property(property="pics", type="array", description="商品图片数组", @SWG\Items(type="string"))
* )
* )
* )
* ),
* @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/GoodsErrorRespones") ) )
* )
*/
public function getBatchItems(Request $request)
{
$authInfo = $request->get('auth');
$itemIdsStr = $request->input('item_ids', '');
if (empty($itemIdsStr)) {
return $this->response->array([]);
}
$itemIds = array_filter(array_map('intval', explode(',', $itemIdsStr)));
if (empty($itemIds)) {
return $this->response->array([]);
}
$itemsRepository = app('registry')->getManager('default')->getRepository(\GoodsBundle\Entities\Items::class);
$cols = 'item_id,item_name,price,pics';
$result = $itemsRepository->getLists(['item_id' => $itemIds], $cols, 1, -1, []);
return $this->response->array($result);
}
}

View File

@@ -144,6 +144,66 @@ class ItemsCategoryService
return 'goods:category:saleable_filter:' . $companyId;
}
/**
* FrontApi 分类列表查询用的 distributor_iditems_category 维度)。
* BBC(standard) 共用平台销售分类platform 使用店铺独立分类。
*/
public function resolveCategoryDistributorIdForFront(string $productModel, int $requestDistributorId): int
{
if ($productModel === 'standard') {
return 0;
}
return $requestDistributorId;
}
/**
* FrontApi 是否按店铺可售商品过滤分类树BBC 店铺主页)。
*/
public function shouldApplySaleableFilterForFront(string $productModel, int $requestDistributorId): bool
{
return $productModel === 'standard' && $requestDistributorId > 0;
}
/**
* 获取店铺可售商品对应的一级销售分类 ID 列表(用于 categorylevel 等扁平接口)。
*/
public function getSaleableTopLevelCategoryIds(int $companyId, int $distributorId): array
{
if ($companyId <= 0 || $distributorId <= 0) {
return [];
}
$categoryIdMap = $this->getSaleableCategoryIdMap($companyId, $distributorId);
if (empty($categoryIdMap)) {
return [];
}
$topLevelIds = [];
foreach (array_keys($categoryIdMap) as $categoryId) {
if (!is_numeric($categoryId)) {
continue;
}
$category = $this->itemsCategoryRepository->getInfo([
'company_id' => $companyId,
'category_id' => (int)$categoryId,
]);
if (!$category) {
continue;
}
if ((int)($category['parent_id'] ?? 0) === 0) {
$topLevelIds[] = (int)$category['category_id'];
} else {
$path = explode(',', (string)($category['path'] ?? ''));
if (!empty($path[0]) && is_numeric($path[0])) {
$topLevelIds[] = (int)$path[0];
}
}
}
return array_values(array_unique($topLevelIds));
}
/**
* 关于节点的回溯
* @param $categories

View File

@@ -29,6 +29,7 @@ use KaquanBundle\Services\DiscountNewGiftCardService;
use KaquanBundle\Services\KaquanService;
use KaquanBundle\Services\DiscountCardService;
use KaquanBundle\Services\UserDiscountService;
use KaquanBundle\Support\ShopDiscountCardListFilter;
class DiscountCard extends BaseController
{
@@ -656,15 +657,12 @@ class DiscountCard extends BaseController
}
$store_self = $request->input('store_self');
$sourceId = floatval($request->get('distributor_id', 0));//如果是平台这里是0
$sourceId = intval($request->get('distributor_id', 0));//如果是平台这里是0
if ($store_self == "true") {//平台版仅支持自营商品【总店】
$filter['or']['distributor_id|like'] = ',0,';
$filter['or']['distributor_id|like'] = '%,%';
} else {
if ($request->get('distributor_id')) {
$filter['or']['distributor_id|like'] = ',' . $request->get('distributor_id') . ',';
$filter['or']['distributor_id|like'] = '%,%';
}
} elseif ($sourceId > 0) {
ShopDiscountCardListFilter::applyToFilter($filter, $sourceId);
}
if ($request->input('receive')) {
@@ -672,10 +670,6 @@ class DiscountCard extends BaseController
}
if ($from == 'btn') {
// 如果来源是按钮出发,平台显示所有的券,店铺显示自己的券
if ($sourceId > 0) {
$filter['source_id'] = $sourceId;
}
$filter['end_date'] = time();//排除已过期的优惠券
}

View File

@@ -0,0 +1,77 @@
<?php
/**
* Copyright 2019-2026 ShopeX
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace KaquanBundle\Support;
/**
* 店铺端优惠券列表可见性过滤(理解 B本店创建 或 适用本店)。
*/
final class ShopDiscountCardListFilter
{
/**
* @param array<string, mixed> $filter
*/
public static function applyToFilter(array &$filter, int $distributorId): bool
{
if ($distributorId <= 0) {
return false;
}
$filter['or'] = self::orConditionsForShop($distributorId);
return true;
}
/**
* @return array<string, mixed>
*/
public static function orConditionsForShop(int $distributorId): array
{
return [
'source_id' => $distributorId,
'use_all_shops' => 1,
// DiscountCardsRepository::__orFilter 的 like 不会自动包裹 %
'distributor_id|like' => '%,' . $distributorId . ',%',
'distributor_id' => ',',
];
}
/**
* @param array<string, mixed> $coupon
*/
public static function matchesCoupon(array $coupon, int $distributorId): bool
{
if ($distributorId <= 0) {
return true;
}
if ((int) ($coupon['source_id'] ?? 0) === $distributorId) {
return true;
}
if (!empty($coupon['use_all_shops']) && (int) $coupon['use_all_shops'] === 1) {
return true;
}
$distributorIdField = (string) ($coupon['distributor_id'] ?? '');
if ($distributorIdField === ',') {
return true;
}
return str_contains($distributorIdField, ',' . $distributorId . ',');
}
}

View File

@@ -1515,9 +1515,63 @@ class Members extends Controller
if (!$memberRegSettingService->checkImageVcode($token, $companyId, $yzmcode, $type)) {
throw new ResourceException(trans('MembersBundle/Members.image_captcha_error'));
}
$memberRegSettingService->generateSmsVcode($mobile, $companyId, $type);
$debugVcode = $memberRegSettingService->generateSmsVcode($mobile, $companyId, $type);
return $this->response->array(['status' => true]);
$response = ['status' => true];
if (is_string($debugVcode)) {
$response['message'] = '短信调试模式已开启';
$response['debug_vcode'] = $debugVcode;
}
return $this->response->array($response);
}
/**
* @SWG\Get(
* path="/member/verify",
* summary="POS 会员手机号验证码校验并查询会员信息",
* tags={"会员"},
* description="POS 场景通过手机号和短信验证码校验会员身份,并返回会员信息,不生成前台会员登录态",
* operationId="verifyMemberByMobileCode",
* @SWG\Parameter(name="mobile", in="query", description="手机号", required=true, type="string"),
* @SWG\Parameter(name="vcode", in="query", description="短信验证码", required=true, type="string"),
* @SWG\Response(response=200, description="成功返回结构"),
* @SWG\Response(response="default", description="错误返回结构", @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/MembersErrorRespones")))
* )
*/
public function verifyMember(Request $request)
{
$companyId = (int) app('auth')->user()->get('company_id');
$mobile = trim((string) $request->input('mobile', ''));
$vcode = trim((string) $request->input('vcode', ''));
if ($mobile === '' || !preg_match('/^1[3456789]\d{9}$/', $mobile)) {
throw new ResourceException(trans('MembersBundle/Members.mobile_error'));
}
if ($vcode === '') {
throw new ResourceException(trans('MembersBundle/Members.verification_code_required'));
}
if (!(new MemberRegSettingService())->checkSmsVcode($mobile, $companyId, $vcode, 'login')) {
throw new ResourceException(trans('MembersBundle/Members.sms_code_error'));
}
$memberInfo = $this->memberService->getInfoByMobile($companyId, $mobile);
if (empty($memberInfo['user_id'])) {
throw new ResourceException(trans('MembersBundle/Members.mobile_not_exists'));
}
return $this->response->array([
'data' => [
'user_id' => $memberInfo['user_id'],
'mobile' => $memberInfo['mobile'] ?? $mobile,
'username' => $memberInfo['username'] ?? '',
'user_card_code' => $memberInfo['user_card_code'] ?? '',
'avatar' => $memberInfo['avatar'] ?? '',
'member_name' => $memberInfo['username'] ?? '',
'member_mobile' => $memberInfo['mobile'] ?? $mobile,
],
]);
}
public function createMember(Request $request)
@@ -1531,13 +1585,13 @@ class Members extends Controller
throw new ResourceException(trans('MembersBundle/Members.invalid_mobile'));
}
/*if (!$postData['vcode']) {
if (empty($postData['vcode'])) {
throw new ResourceException(trans('MembersBundle/Members.verification_code_required'));
}
if (!(new MemberRegSettingService())->checkSmsVcode($postData['mobile'], $companyId, $postData['vcode'], $postData['check_type'] ?? 'sign')) {
throw new ResourceException(trans('MembersBundle/Members.sms_code_error'));
}*/
}
$memberInfo = $this->memberService->getInfoByMobile((int)$companyId, (string)$postData['mobile']);
if ($memberInfo) {
@@ -1559,7 +1613,7 @@ class Members extends Controller
//新增-会员信息
$memberInfo = [
'company_id' => $companyId,
'username' => randValue(8),
'username' => $postData['name'] ?? randValue(8),
'mobile' => $postData['mobile'],
'grade_id' => $defaultGradeInfo['grade_id'],
'password' => substr(str_shuffle('QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm'), 5, 10),

View File

@@ -1247,8 +1247,13 @@ class Members extends Controller
}
}
}
$memberRegSettingService->generateSmsVcode($phone, $companyId, $type);
return $this->response->array(['message' => "短信发送成功"]);
$debugVcode = $memberRegSettingService->generateSmsVcode($phone, $companyId, $type);
$response = ['message' => "短信发送成功"];
if (is_string($debugVcode)) {
$response['message'] = '短信调试模式已开启';
$response['debug_vcode'] = $debugVcode;
}
return $this->response->array($response);
}
/**

View File

@@ -231,6 +231,10 @@ class MemberRegSettingService
app('log')->info("code :" . json_encode(['phone' => $phone, 'company' => $companyId, 'vcode' => $vcode]));
//保存验证码
$this->saveSmsVcode($phone, $companyId, $vcode, $type);
if (config("common.sms_debug_vcode")) {
app('log')->info("member sms debug vcode enabled :" . json_encode(['phone' => $phone, 'company' => $companyId, 'type' => $type]));
return $vcode;
}
//发送短信
$this->sendSmsVcode($companyId, $phone, $vcode, $type);
return true;

View File

@@ -1875,7 +1875,7 @@ class Order extends Controller
$setting['latest_aftersale_time'] = $input['latest_aftersale_time'] ?? 0; //默认确认收货后不可申请售后
$setting['auto_refuse_time'] = $input['auto_refuse_time'] ?? 0; //默认确认收货后不可申请售后
$setting['auto_aftersales'] = isset($input['auto_aftersales']) && $input['auto_aftersales'] && $input['auto_aftersales'] != 'false'; // 未发货售后自动同意
$setting['offline_aftersales'] = isset($input['offline_aftersales']) && $input['offline_aftersales'] && $input['offline_aftersales'] != 'false'; // 到店退货
$setting['offline_aftersales'] = isset($input['offline_aftersales']) && ($input['offline_aftersales'] === 'true' || $input['offline_aftersales'] === true); // 到店退货
$setting['is_refund_freight'] = $input['is_refund_freight'] ?? 0; // 退货退款可退运费
if ($setting['is_refund_freight'] == 1) {

View File

@@ -48,7 +48,7 @@ class DistributorCartObject implements CartInterface
public function checkItemParams($params)
{
// 检查是否是有效的会员优先购
$memberpreference = $this->checkCurrentMemberpreferenceByItemId($params['company_id'], $params['user_id'], $params['item_id'], $params['shop_id'], false, $msg);
$memberpreference = $this->checkCurrentMemberpreferenceByItemId($params['company_id'], $params['user_id'], $params['item_id'], $msg, $params['shop_id'], false);
if (!$memberpreference) {
throw new ResourceException($msg);
}

View File

@@ -662,7 +662,7 @@ class CartService
$memberpreference = true;
$cartdata['shop_type'] = $cartdata['shop_type'] ?? '';
if ($cartType != 'employee_purchase' && ($cartdata['shop_type'] != 'pointsmall' && $cartdata['shop_type'] != 'shop_offline')) {
$memberpreference = $this->checkCurrentMemberpreferenceByItemId($companyId, $userId, $itemId, $cartdata['shop_id'], false, $msg);
$memberpreference = $this->checkCurrentMemberpreferenceByItemId($companyId, $userId, $itemId, $msg, $cartdata['shop_id'], false);
}
if (!$memberpreference) {
$invalidCart[] = $cartdata;

View File

@@ -1370,7 +1370,7 @@ class OrderService
$itemsCommissionService = new ItemsCommissionService();
foreach ($this->orderItemList as $itemInfo) {
if (!in_array($this->orderInterface->orderClass, ['pointsmall', 'employee_purchase'])) {
$memberpreference = $this->checkCurrentMemberpreferenceByItemId($orderData['company_id'], $orderData['user_id'], $itemInfo['itemId'], $orderData['distributor_id'], false, $msg);
$memberpreference = $this->checkCurrentMemberpreferenceByItemId($orderData['company_id'], $orderData['user_id'], $itemInfo['itemId'], $msg, $orderData['distributor_id'], false);
if (!$memberpreference) {
$orderData['extraTips'] = $msg;
if ($isCheck) {

View File

@@ -81,15 +81,30 @@ trait GetOrderIdTrait
$identityOrderId = $promoterOrderId = [];
$is_promoter_identity = $is_promoter_mobile = false;
if (isset($filter['promoter_identity']) && $filter['promoter_identity']) {
$sql = "select promoter.user_id from popularize_promoter promoter left join popularize_promoter_identity identity on promoter.identity_id=identity.id where promoter.company_id=".$filter['company_id']." and identity.name='".$filter['promoter_identity']."'";
$lists = $conn->executeQuery($sql)->fetchAll();
$qb = $conn->createQueryBuilder();
$lists = $qb->select('promoter.user_id')
->from('popularize_promoter', 'promoter')
->leftJoin('promoter', 'popularize_promoter_identity', 'identity', 'promoter.identity_id = identity.id')
->where($qb->expr()->eq('promoter.company_id', $qb->expr()->literal($filter['company_id'])))
->andWhere($qb->expr()->eq('identity.name', $qb->expr()->literal($filter['promoter_identity'])))
->execute()
->fetchAll();
$userIds = array_column($lists, 'user_id');
$userIds = array_filter($userIds, function($value) {
return $value !== null && $value !== false && $value !== "" && $value !== 0;
});
if ($userIds) {
$sql = "select id,order_id,user_id,buy_user_id from popularize_brokerage where company_id=".$filter['company_id']." and brokerage_type='first_level' and user_id in (".implode($userIds, ',').")";
$lists = $conn->executeQuery($sql)->fetchAll();
$qb = $conn->createQueryBuilder();
$userIdLiterals = array_map(function ($value) use ($qb) {
return $qb->expr()->literal($value);
}, $userIds);
$lists = $qb->select('id', 'order_id', 'user_id', 'buy_user_id')
->from('popularize_brokerage')
->where($qb->expr()->eq('company_id', $qb->expr()->literal($filter['company_id'])))
->andWhere($qb->expr()->eq('brokerage_type', $qb->expr()->literal('first_level')))
->andWhere($qb->expr()->in('user_id', $userIdLiterals))
->execute()
->fetchAll();
$identityOrderId = array_column($lists, 'order_id');
$identityOrderId = array_filter($identityOrderId, function($value) {
return $value !== null && $value !== false && $value !== "" && $value !== 0;
@@ -102,8 +117,14 @@ trait GetOrderIdTrait
$memberService = new MemberService();
$userId = $memberService->getUserIdByMobile($filter['promoter_mobile'], $filter['company_id']);
if ($userId) {
$sql = "select brokerage.order_id from popularize_promoter promoter left join popularize_brokerage brokerage on promoter.user_id=brokerage.user_id where promoter.company_id=".$filter['company_id']." and promoter.user_id=".$userId;
$lists = $conn->executeQuery($sql)->fetchAll();
$qb = $conn->createQueryBuilder();
$lists = $qb->select('brokerage.order_id')
->from('popularize_promoter', 'promoter')
->leftJoin('promoter', 'popularize_brokerage', 'brokerage', 'promoter.user_id = brokerage.user_id')
->where($qb->expr()->eq('promoter.company_id', $qb->expr()->literal($filter['company_id'])))
->andWhere($qb->expr()->eq('promoter.user_id', $qb->expr()->literal($userId)))
->execute()
->fetchAll();
$promoterOrderId = array_column($lists, 'order_id');
$promoterOrderId = array_filter($promoterOrderId, function($value) {
return $value !== null && $value !== false && $value !== "" && $value !== 0;
@@ -151,8 +172,18 @@ trait GetOrderIdTrait
// p_promoter_mobile:上级推广员手机号
// promoter_is_close:是否结算
$orderIds = array_column($orderLists, 'order_id');
$sql = "select order_id,user_id,is_close from popularize_brokerage where brokerage_type='first_level' and source='order' and order_id in (".implode($orderIds, ',').")";
$userLists = $conn->executeQuery($sql)->fetchAll();
$literalQb = $conn->createQueryBuilder();
$orderIdLiterals = array_map(function ($value) use ($literalQb) {
return $literalQb->expr()->literal($value);
}, $orderIds);
$qb = $conn->createQueryBuilder();
$userLists = $qb->select('order_id', 'user_id', 'is_close')
->from('popularize_brokerage')
->where($qb->expr()->eq('brokerage_type', $qb->expr()->literal('first_level')))
->andWhere($qb->expr()->eq('source', $qb->expr()->literal('order')))
->andWhere($qb->expr()->in('order_id', $orderIdLiterals))
->execute()
->fetchAll();
$userIds = array_column($userLists, 'user_id');
$userIds = array_filter($userIds, function($value) {
return $value !== null && $value !== false && $value !== "" && $value !== 0;
@@ -162,8 +193,22 @@ trait GetOrderIdTrait
}
$result = [];
// 查询推广员
$sql = "select promoter.user_id,promoter.promoter_name,promoter.pname p_promoter_name,promoter.pmobile p_promoter_mobile,identity.name promoter_identity from popularize_promoter promoter left join popularize_promoter_identity identity on promoter.identity_id=identity.id where promoter.user_id in (".implode($userIds, ',').")";
$promoterLists = $conn->executeQuery($sql)->fetchAll();
$userIdLiterals = array_map(function ($value) use ($literalQb) {
return $literalQb->expr()->literal($value);
}, $userIds);
$qb = $conn->createQueryBuilder();
$promoterLists = $qb->select(
'promoter.user_id',
'promoter.promoter_name',
'promoter.pname AS p_promoter_name',
'promoter.pmobile AS p_promoter_mobile',
'identity.name AS promoter_identity'
)
->from('popularize_promoter', 'promoter')
->leftJoin('promoter', 'popularize_promoter_identity', 'identity', 'promoter.identity_id = identity.id')
->where($qb->expr()->in('promoter.user_id', $userIdLiterals))
->execute()
->fetchAll();
$promoterLists = array_column($promoterLists, null, 'user_id');
// 查询推广员手机号
@@ -175,16 +220,35 @@ trait GetOrderIdTrait
$promoterData[$value['order_id']]['promoter_is_close'] = $value['is_close'];
}
// 查询订单分佣金额
$where = "company_id=".$companyId." and order_id in (".implode($orderIds, ',').") and source='order'";
$sql = "select order_id,sum(rebate) order_total_rebate from popularize_brokerage where ".$where." group by order_id";
$orderRebate = $conn->executeQuery($sql)->fetchAll();
$buildBrokerageRebateQuery = function ($brokerageType = null) use ($conn, $companyId, $orderIdLiterals) {
$qb = $conn->createQueryBuilder();
$qb->from('popularize_brokerage')
->where($qb->expr()->eq('company_id', $qb->expr()->literal($companyId)))
->andWhere($qb->expr()->in('order_id', $orderIdLiterals))
->andWhere($qb->expr()->eq('source', $qb->expr()->literal('order')));
if ($brokerageType !== null) {
$qb->andWhere($qb->expr()->eq('brokerage_type', $qb->expr()->literal($brokerageType)));
}
return $qb;
};
$orderRebate = $buildBrokerageRebateQuery()
->select('order_id', 'SUM(rebate) AS order_total_rebate')
->groupBy('order_id')
->execute()
->fetchAll();
$orderRebate = array_column($orderRebate, null, 'order_id');
// 查询订单分佣金额
$sql = "select order_id,sum(rebate) as rebate from popularize_brokerage where ".$where." and brokerage_type='first_level' group by order_id";
$firstRebate = $conn->executeQuery($sql)->fetchAll();
$firstRebate = $buildBrokerageRebateQuery('first_level')
->select('order_id', 'SUM(rebate) AS rebate')
->groupBy('order_id')
->execute()
->fetchAll();
$firstRebate = array_column($firstRebate, null, 'order_id');
$sql = "select order_id,sum(rebate) as rebate from popularize_brokerage where ".$where." and brokerage_type='second_level' group by order_id";
$secondRebate = $conn->executeQuery($sql)->fetchAll();
$secondRebate = $buildBrokerageRebateQuery('second_level')
->select('order_id', 'SUM(rebate) AS rebate')
->groupBy('order_id')
->execute()
->fetchAll();
$secondRebate = array_column($secondRebate, null, 'order_id');
foreach ($orderIds as $order_id) {
if (isset($promoterData[$order_id])) {

View File

@@ -246,7 +246,7 @@ trait CheckPromotionsValid
* @param inteter $itemId 商品详情也的商品ID也是默认商品ID
* @param bool $isItemsAll 如果商品为多规格商品是否需要查询所有的SKU信息
*/
public function checkCurrentMemberpreferenceByItemId($companyId, $userId, $itemId, $distributorId = null, $isItemsAll = true, &$msg)
public function checkCurrentMemberpreferenceByItemId($companyId, $userId, $itemId, &$msg, $distributorId = null, $isItemsAll = true)
{
$itemsService = new ItemsService();
$itemInfo = $itemsService->getInfo(['item_id' => $itemId, 'company_id' => $companyId]);

View File

@@ -60,17 +60,28 @@ class OpenScreenAd extends Controller
*/
public function getInfo(Request $request)
{
// CONST: 1E236443
$params = $request->all('company_id');
$auth_info = $request->get('auth');
$filter['company_id'] = $auth_info['company_id'];
$filter['is_enable'] = 1;
$filter['start_time|lte'] = time();
$filter['end_time|gte'] = time();
$OpenScreenAd = new OpenScreenAdServices();
$data = $OpenScreenAd->lists($filter, '*', 1, 1);
$result = !empty($data['list']) ? reset($data['list']) : [];
// 只有配置了开始/结束时间才校验;都是 0 表示不限期(管理端未传时间时的默认值)
if (!empty($result)) {
$now = time();
$startTime = (int) ($result['start_time'] ?? 0);
$endTime = (int) ($result['end_time'] ?? 0);
if (!($startTime === 0 && $endTime === 0)) {
if ($startTime > 0 && $startTime > $now) {
$result = [];
} elseif ($endTime > 0 && $endTime < $now) {
$result = [];
}
}
}
if ($result) {
$result['ad_url'] = json_decode($result['ad_url'], true);
}

View File

@@ -122,12 +122,6 @@ class PagesTemplate extends Controller
if ($result['data']) {
$result['data'] = $itemsService->applyMultiSpecTotalStoreForItemList($result['data']);
}
if ($eActivityId > 0 && $result['data']) {
$activityItemsService = new ActivityItemsService();
$wrapped = ['list' => $result['data']];
$wrapped = $activityItemsService->getItemsListActityPrice($wrapped, $eActivityId, (int) $params['company_id']);
$result['data'] = $wrapped['list'];
}
if ($result['data']) {
$result['data'] = $itemsService->getItemsListMemberPrice($result['data'], $authInfo['user_id'], $params['company_id']);
}
@@ -139,6 +133,13 @@ class PagesTemplate extends Controller
$promotionType = '';
}
$result['data'] = $itemsService->getItemsListActityTag($result['data'], $params['company_id'], $params['regionauth_id'], $params['user_id'], $promotionId, $promotionType, 'include_not_start');
// 内购活动价最后覆盖,避免被营销标签 activity_price 覆盖
if ($eActivityId > 0 && $result['data']) {
$activityItemsService = new ActivityItemsService();
$wrapped = ['list' => $result['data']];
$wrapped = $activityItemsService->getItemsListActityPrice($wrapped, $eActivityId, (int) $params['company_id']);
$result['data'] = $wrapped['list'];
}
}
//优惠券标签

View File

@@ -73,8 +73,8 @@ class OpenScreenAdServices
$saveAdd['waiting_time'] = $params['waiting_time'];
$saveAdd['ad_url'] = $params['ad_url'];
$saveAdd['app'] = $params['app'];
$saveAdd['start_time'] = $params['start_time'];
$saveAdd['end_time'] = $params['end_time'];
$saveAdd['start_time'] = ($params['start_time'] !== null && $params['start_time'] !== '') ? (int) $params['start_time'] : 0;
$saveAdd['end_time'] = ($params['end_time'] !== null && $params['end_time'] !== '') ? (int) $params['end_time'] : 0;
return $this->saveAdd($saveAdd);
} else {
$saveUpdate['ad_material'] = $params['ad_material'];
@@ -86,8 +86,13 @@ class OpenScreenAdServices
$saveUpdate['waiting_time'] = $params['waiting_time'];
$saveUpdate['ad_url'] = $params['ad_url'];
$saveUpdate['app'] = $params['app'];
$saveUpdate['start_time'] = $params['start_time'];
$saveUpdate['end_time'] = $params['end_time'];
// 没传 start_time / end_time 时不更新,避免每次保存都写成 0
if ($params['start_time'] !== null && $params['start_time'] !== '') {
$saveUpdate['start_time'] = (int) $params['start_time'];
}
if ($params['end_time'] !== null && $params['end_time'] !== '') {
$saveUpdate['end_time'] = (int) $params['end_time'];
}
$saveUpdate['updated'] = time();
return $this->saveUpdate($company_id, $saveUpdate);

View File

@@ -1401,7 +1401,7 @@ class PagesTemplateServices
if (!$distributor_ids) {
break;
}
$distributor_list = $distributorService->entityRepository->getLists(['distributor_id' => $distributor_ids], 'distributor_id, name, logo, first_letter, tag_name, tag_start_time, tag_end_time');
$distributor_list = $distributorService->entityRepository->getLists(['distributor_id' => $distributor_ids], 'distributor_id, name, logo, first_letter');
if (!$distributor_list) {
break;
}
@@ -1421,10 +1421,6 @@ class PagesTemplateServices
if (!$distributor_info) {
continue;
}
//店铺标签不在有效期内
if (intval($distributor_info['tag_start_time']) > time() or intval($distributor_info['tag_end_time']) < time()) {
$distributor_info['tag_name'] = '';
}
$child_data_v = array_merge($child_data_v, $distributor_info);
$child_v['data'][$child_data_k] = $child_data_v;
}
@@ -1445,7 +1441,7 @@ class PagesTemplateServices
if (!$distributor_ids) {
break;
}
$distributor_list = $distributorService->entityRepository->getLists(['distributor_id' => $distributor_ids], 'distributor_id, name, logo, first_letter, tag_name, tag_start_time, tag_end_time');
$distributor_list = $distributorService->entityRepository->getLists(['distributor_id' => $distributor_ids], 'distributor_id, name, logo, first_letter');
if (!$distributor_list) {
break;
}
@@ -1456,10 +1452,6 @@ class PagesTemplateServices
if (!$distributor_info) {
continue;
}
//店铺标签不在有效期内
if (intval($distributor_info['tag_start_time']) > time() or intval($distributor_info['tag_end_time']) < time()) {
$distributor_info['tag_name'] = '';
}
$tmp_v = array_merge($tmp_v, $distributor_info);
$params['data'][$tmp_k] = $tmp_v;
}

View File

@@ -761,7 +761,7 @@ class Wxa extends Controller
$list = $settingService->getTemplateConf($companyId, $templateName, $pageName, $name, $version);
if (!isset($list[0]['params']['is_open'])) {
if (!empty($list) && !isset($list[0]['params']['is_open'])) {
$list[0]['params']['is_open'] = true;
}
@@ -1265,5 +1265,4 @@ class Wxa extends Controller
return $this->response->array($response);
}
}