diff --git a/README.md b/README.md index a41121a..46e880e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -


English / 简体中文
@@ -189,6 +189,10 @@ Launch using 'php server' php -S 127.0.0.1:9058 -t public ``` +### The initial administrator account credentials for the system are: +Username: admin +Password: Shopex123 + ## License This project is licensed under the Apache-2.0 open-source license. Each ECShopX source file included in this distribution is licensed under the Apache License 2.0. diff --git a/README_cn.md b/README_cn.md index ef75524..4bd52b8 100644 --- a/README_cn.md +++ b/README_cn.md @@ -1,4 +1,4 @@ -

English / 简体中文
diff --git a/bootstrap/app.php b/bootstrap/app.php index 7f2351b..12c4c66 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -91,6 +91,7 @@ $app->configure('oms'); $app->configure('shopexai'); $app->configure('tbitems'); $app->configure('paypal'); +$app->configure('langue'); /* |-------------------------------------------------------------------------- diff --git a/composer.json b/composer.json index 17ef032..0daf405 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "laravel/lumen", - "version": "4.2.1", + "version": "4.2.2", "description": "The Laravel Lumen Framework.", "keywords": ["framework", "laravel", "lumen"], "license": "MIT", diff --git a/config/langue.php b/config/langue.php new file mode 100644 index 0000000..6ac2ded --- /dev/null +++ b/config/langue.php @@ -0,0 +1,8 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + + $this->addSql('ALTER TABLE items_category ADD category_id_taobao BIGINT DEFAULT 0 COMMENT \'淘宝分类id\', ADD parent_id_taobao BIGINT DEFAULT 0 COMMENT \'淘宝父级分类ID\', ADD taobao_category_info JSON DEFAULT NULL COMMENT \'淘宝分类信息行(DC2Type:json_array)\''); + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + + // $this->addSql('ALTER TABLE items_category DROP category_id_taobao, DROP parent_id_taobao, DROP taobao_category_info'); + + } +} diff --git a/database/migrations/Version20250707100134.php b/database/migrations/Version20250707100134.php new file mode 100644 index 0000000..7aaf0f3 --- /dev/null +++ b/database/migrations/Version20250707100134.php @@ -0,0 +1,30 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('ALTER TABLE items ADD is_taobao INT DEFAULT 0 COMMENT \'是否淘宝商品\''); + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + + } +} diff --git a/database/migrations/Version20260108161332.php b/database/migrations/Version20260108161332.php new file mode 100644 index 0000000..f85507c --- /dev/null +++ b/database/migrations/Version20260108161332.php @@ -0,0 +1,26 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + $this->addSql('ALTER TABLE distribution_distributor ADD payment_subject SMALLINT DEFAULT 0 NOT NULL COMMENT \'收款主体,0=平台,1=店铺\', CHANGE created created bigint NOT NULL, CHANGE updated updated bigint NOT NULL'); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + } +} \ No newline at end of file diff --git a/resources/lang/en-CN/DistributionBundle/Services/DistributorService.php b/resources/lang/en-CN/DistributionBundle/Services/DistributorService.php index 53012e1..8ee19df 100644 --- a/resources/lang/en-CN/DistributionBundle/Services/DistributorService.php +++ b/resources/lang/en-CN/DistributionBundle/Services/DistributorService.php @@ -10,6 +10,14 @@ $error = [ 'jst_shop_bound' => 'Current JST ERP store number has been bound by other stores', 'confirm_update_data' => 'Please confirm if the update data is correct', 'shop_info_query_failed' => 'Store information query failed', + 'distributor_not_exists_or_no_permission' => 'Distributor does not exist or no permission', + 'has_unfinished_refund_cannot_switch_payment_subject' => 'There are unfinished refund orders, cannot switch payment subject', + 'switch_to_distributor_payment_subject_need_at_least_one_payment' => 'When switching to distributor payment subject, at least one payment method (WeChat Pay or Alipay) must be enabled', + 'wxpay_config_incomplete' => 'WeChat Pay configuration is incomplete, please complete the configuration before switching payment subject', + 'distributor_wxpay_config_incomplete' => 'Distributor WeChat Pay configuration is incomplete, please complete the configuration before switching payment subject', + 'platform_wxpay_config_incomplete' => 'Platform WeChat Pay configuration is incomplete, please complete the configuration before switching payment subject', + 'distributor_alipay_config_incomplete' => 'Distributor Alipay configuration is incomplete, please complete the configuration before switching payment subject', + 'platform_alipay_config_incomplete' => 'Platform Alipay configuration is incomplete, please complete the configuration before switching payment subject', ]; // Business Data diff --git a/resources/lang/en-CN/GoodsBundle/Controllers/Items.php b/resources/lang/en-CN/GoodsBundle/Controllers/Items.php index ddbc802..f66cf04 100644 --- a/resources/lang/en-CN/GoodsBundle/Controllers/Items.php +++ b/resources/lang/en-CN/GoodsBundle/Controllers/Items.php @@ -45,6 +45,7 @@ $itemsService = [ 'brand_name_duplicate' => 'Brand name cannot be duplicated', 'param_value_cannot_be_empty' => 'Parameter value cannot be empty', 'has_associated_items' => 'There are associated products, please handle the associated products first', + 'has_associated_pointsmall_items' => 'There are associated pointsmall products, please handle the associated pointsmall products first', 'value_has_associated_items' => 'Value has associated products, please handle the associated products first', 'update_data_not_exists' => 'Update data does not exist', diff --git a/resources/lang/en-CN/PromotionsBundle.php b/resources/lang/en-CN/PromotionsBundle.php index 27a3f12..c653c12 100644 --- a/resources/lang/en-CN/PromotionsBundle.php +++ b/resources/lang/en-CN/PromotionsBundle.php @@ -165,21 +165,21 @@ return [ 'delete_data_not_exist' => 'Delete data does not exist', 'sms_signature_not_exist' => 'SMS signature does not exist for update', 'no_promotion_rule_specified' => 'No promotion rule specified', - 'bargain_activity_not_exist_with_id' => 'Bargain activity with bargain_id={bargain_id} does not exist', - 'bargain_activity_delete_not_exist_with_id' => 'Bargain activity with bargain_id={bargain_id} does not exist for deletion', - 'marketing_activity_not_exist_with_id' => 'Marketing activity with marketing_id={marketing_id} does not exist', - 'seckill_activity_not_exist_with_id' => 'Seckill activity with seckill_id={seckill_id} does not exist', - 'promotion_group_activity_not_exist_with_id' => 'Group activity with group_id={group_id} does not exist', - 'package_not_exist_with_id' => 'Package with package_id={package_id} does not exist', - 'point_activity_not_exist_with_id' => 'Point activity with activity_id={activity_id} does not exist', - 'user_task_activity_not_exist_with_id' => 'User task activity with activity_id={activity_id} does not exist', - 'user_signin_rule_not_exist_with_id' => 'User signin rule with activity_id={activity_id} does not exist', - 'turntable_activity_not_exist_with_id' => 'Turntable activity with activity_id={activity_id} does not exist', - 'specific_crowd_discount_not_exist_with_id' => 'Specific crowd discount with discount_id={discount_id} does not exist', - 'user_bargain_activity_not_exist' => 'The bargain activity with bargain_id={bargain_id} you participated in does not exist', + 'bargain_activity_not_exist_with_id' => 'Bargain activity with bargain_id=:bargain_id does not exist', + 'bargain_activity_delete_not_exist_with_id' => 'Bargain activity with bargain_id=:bargain_id does not exist for deletion', + 'marketing_activity_not_exist_with_id' => 'Marketing activity with marketing_id=:marketing_id does not exist', + 'seckill_activity_not_exist_with_id' => 'Seckill activity with seckill_id=:seckill_id does not exist', + 'promotion_group_activity_not_exist_with_id' => 'Group activity with group_id=:group_id does not exist', + 'package_not_exist_with_id' => 'Package with package_id=:package_id does not exist', + 'point_activity_not_exist_with_id' => 'Point activity with activity_id=:activity_id does not exist', + 'user_task_activity_not_exist_with_id' => 'User task activity with activity_id=:activity_id does not exist', + 'user_signin_rule_not_exist_with_id' => 'User signin rule with activity_id=:activity_id does not exist', + 'turntable_activity_not_exist_with_id' => 'Turntable activity with activity_id=:activity_id does not exist', + 'specific_crowd_discount_not_exist_with_id' => 'Specific crowd discount with discount_id=:discount_id does not exist', + 'user_bargain_activity_not_exist' => 'The bargain activity with bargain_id=:bargain_id you participated in does not exist', // Services error messages - 'activity_not_exist_with_id' => 'Error, activity with id: {id} does not exist', + 'activity_not_exist_with_id' => 'Error, activity with id: :id does not exist', 'activity_not_exist_or_wrong_id' => 'Error, activity does not exist or wrong ID', 'turntable_activity_not_enabled' => 'Turntable activity is not enabled', 'not_in_activity_time' => 'Not within activity time', @@ -189,11 +189,11 @@ return [ 'draw_activity_not_started' => 'Draw activity has not started', 'insufficient_user_points' => 'Insufficient user points', 'draw_times_reach_activity_limit' => 'Draw times reach activity limit', - 'daily_sms_limit_reached' => 'Daily SMS sending limit reached {max_times} times', + 'daily_sms_limit_reached' => 'Daily SMS sending limit reached :max_times times', 'register_title_required' => 'Registration title is required', 'please_select_ad_image' => 'Please select advertisement image', 'please_select_distributor' => 'Please select distributor', - 'bargain_activity_not_exist_with_bargain_id' => 'Bargain activity with bargain_id {bargain_id} does not exist!', + 'bargain_activity_not_exist_with_bargain_id' => 'Bargain activity with bargain_id :bargain_id does not exist!', 'please_select_specific_gift_date' => 'Please select specific gift date', 'please_select_date' => 'Please select date', 'activity_start_time_cannot_greater_than_end_time' => 'Activity start time cannot be greater than end time', @@ -214,7 +214,7 @@ return [ 'please_select_promotion_area' => 'Please select promotion area', 'sms_template_format_error' => 'SMS template format error, no variables detected', 'sms_template_variables_too_many' => 'Too many SMS template variables, maximum 20 variables supported', - 'sms_template_variable_length_error' => 'SMS template variable length exceeds limit: {variable_name}', + 'sms_template_variable_length_error' => 'SMS template variable length exceeds limit: :variable_name', 'promotion_activity_time_conflict' => 'Marketing activity already exists in the selected time range', 'activity_not_exist_error' => 'Error, activity does not exist', 'points_task_not_exist_error' => 'Error, points task does not exist', @@ -308,11 +308,11 @@ return [ 'applicable_platform_required' => 'Applicable platform is required', 'regular_crossborder_cannot_package' => 'Regular and cross-border products cannot be sold as package', 'activity_start_time_cannot_greater_than_publish' => 'Activity start time cannot be greater than publish time', - 'product_stock_required_greater_than_zero' => 'Product {item_title} stock is required and must be greater than 0', - 'product_price_required_greater_than_zero' => 'Product {item_title} price is required and must be greater than 0', - 'product_limit_required_greater_than_zero' => 'Product {item_title} limit is required and must be greater than 0', + 'product_stock_required_greater_than_zero' => 'Product :item_title stock is required and must be greater than 0', + 'product_price_required_greater_than_zero' => 'Product :item_title price is required and must be greater than 0', + 'product_limit_required_greater_than_zero' => 'Product :item_title limit is required and must be greater than 0', 'current_activity_not_editable' => 'Current activity is not editable', - 'store_has_valid_activity_same_time' => 'Store id={id} has valid activity in the same time period', + 'store_has_valid_activity_same_time' => 'Store id=:id has valid activity in the same time period', 'import_file_unrecognizable' => 'Import file is unrecognizable', 'error_rows_too_many_show_100' => 'Too many error rows, system only shows first 100 rows.', 'signature_not_set_cannot_send_sms' => 'Signature not set, cannot send SMS', @@ -325,12 +325,11 @@ return [ // User related Service files error messages 'activity_ended_expect_next_participation' => 'Activity has ended, looking forward to your next participation!', 'activity_not_started_please_wait' => 'Activity has not started yet, please wait!', -]; + // UserSign subdirectory error messages 'error_already_signed_today' => 'Error, you have already signed in today', 'error_prize_already_exists' => 'Error, prize for this day already exists', 'data_not_exist' => 'This data does not exist', -]; // Common error messages 'bargain_help_detail_not_found' => 'Bargain help detail not found!', @@ -343,8 +342,7 @@ return [ 'please_select_main_category' => 'Please select main category', 'please_select_tags' => 'Please select tags', 'please_select_brand' => 'Please select brand', - 'product_inventory_insufficient' => 'Product {item_name} inventory insufficient!', -]; + 'product_inventory_insufficient' => 'Product :item_name inventory insufficient!', // Group activity related error messages 'invalid_product' => 'Invalid product', @@ -365,7 +363,7 @@ return [ 'end_time_greater_than_start' => 'End time must be greater than start time', 'product_not_found' => 'Product not found', 'group_price_cannot_greater_than_sale_price' => 'Group price cannot be greater than product sale price, please check and resubmit!', - 'group_price_cannot_greater_than_store_price' => 'Group price cannot be greater than store (Store ID: {store_id}) sale price, please check and resubmit!', + 'group_price_cannot_greater_than_store_price' => 'Group price cannot be greater than store (Store ID: :store_id) sale price, please check and resubmit!', // Group team related validation 'company_id_required' => 'Company ID is required', diff --git a/resources/lang/en-CN/SelfserviceBundle.php b/resources/lang/en-CN/SelfserviceBundle.php index b420b40..3e69019 100644 --- a/resources/lang/en-CN/SelfserviceBundle.php +++ b/resources/lang/en-CN/SelfserviceBundle.php @@ -7,14 +7,14 @@ return [ // Registration activity related 'activity_not_exist' => 'Activity does not exist', - 'parameter_error' => 'Parameter error: {status}', + 'parameter_error' => 'Parameter error: :status', 'only_members_can_register' => 'Only members can participate in registration', 'please_specify_registration_activity' => 'Please specify registration activity', 'activity_too_popular_try_later' => 'Activity is too popular, please try again later', 'activity_too_popular_try_later_short' => 'Activity is too popular, please try again later', 'registration_data_cannot_empty' => 'Registration data cannot be empty', - 'field_required' => '{field_title} is required', - 'field_required_with_card' => '{field_title} under {card_title} is required', + 'field_required' => ':field_title is required', + 'field_required_with_card' => ':field_title under :card_title is required', 'please_enter_correct_mobile' => 'Please enter a valid mobile number', 'activity_registration_not_allow_modify' => 'Activity registration cannot be modified', 'please_fill_registration_form' => 'Please fill in the registration form', @@ -90,9 +90,9 @@ return [ // Other service error messages 'data_error' => 'Data error', - 'field_required_simple' => '{field_title} is required', - 'field_must_be_number' => '{field_title} must be a number', - 'activity_group_code_error' => 'Activity group code error: {group_no}', + 'field_required_simple' => ':field_title is required', + 'field_must_be_number' => ':field_title must be a number', + 'activity_group_code_error' => 'Activity group code error: :group_no', // checkActivityValid method error messages 'activity_not_exist_err' => 'Activity does not exist', diff --git a/resources/lang/zh-CN/DistributionBundle/Services/DistributorService.php b/resources/lang/zh-CN/DistributionBundle/Services/DistributorService.php index 2d91028..7d1ded6 100644 --- a/resources/lang/zh-CN/DistributionBundle/Services/DistributorService.php +++ b/resources/lang/zh-CN/DistributionBundle/Services/DistributorService.php @@ -10,6 +10,14 @@ $error = [ 'jst_shop_bound' => '当前聚水潭ERP店铺编号已经被其他店铺绑定', 'confirm_update_data' => '请确认修改数据是否正确', 'shop_info_query_failed' => '店铺信息查询失败', + 'distributor_not_exists_or_no_permission' => '店铺不存在或无权限', + 'has_unfinished_refund_cannot_switch_payment_subject' => '有未完成的退款单,不允许切换收款主体', + 'switch_to_distributor_payment_subject_need_at_least_one_payment' => '切换为店铺收款主体时,至少需要开启微信支付或支付宝支付中的一种', + 'wxpay_config_incomplete' => '微信支付配置不完整,请先完成配置后再切换收款主体', + 'distributor_wxpay_config_incomplete' => '店铺微信支付配置不完整,请先完成配置后再切换收款主体', + 'platform_wxpay_config_incomplete' => '平台微信支付配置不完整,请先完成配置后再切换收款主体', + 'distributor_alipay_config_incomplete' => '店铺支付宝配置不完整,请先完成配置后再切换收款主体', + 'platform_alipay_config_incomplete' => '平台支付宝配置不完整,请先完成配置后再切换收款主体', ]; // 业务数据 diff --git a/resources/lang/zh-CN/GoodsBundle/Controllers/Items.php b/resources/lang/zh-CN/GoodsBundle/Controllers/Items.php index 6d4ddbf..a4b1baa 100644 --- a/resources/lang/zh-CN/GoodsBundle/Controllers/Items.php +++ b/resources/lang/zh-CN/GoodsBundle/Controllers/Items.php @@ -45,6 +45,7 @@ $itemsService = [ 'brand_name_duplicate' => '品牌名称不能重复', 'param_value_cannot_be_empty' => '参数值不能为空', 'has_associated_items' => '有关联商品,请先处理关联的商品', + 'has_associated_pointsmall_items' => '有关联积分商城商品,请先处理关联的积分商城商品', 'value_has_associated_items' => '数值有关联商品,请先处理关联的商品', 'update_data_not_exists' => '更新的数据不存在', diff --git a/resources/lang/zh-CN/PromotionsBundle.php b/resources/lang/zh-CN/PromotionsBundle.php index 86737be..04a81d8 100644 --- a/resources/lang/zh-CN/PromotionsBundle.php +++ b/resources/lang/zh-CN/PromotionsBundle.php @@ -165,21 +165,21 @@ return [ 'delete_data_not_exist' => '删除的数据不存在', 'sms_signature_not_exist' => '更新短信签名不存在', 'no_promotion_rule_specified' => '没有指定促销规则', - 'bargain_activity_not_exist_with_id' => 'bargain_id={bargain_id}的砍价活动不存在', - 'bargain_activity_delete_not_exist_with_id' => 'bargain_id={bargain_id}的助力活动不存在', - 'marketing_activity_not_exist_with_id' => 'marketing_id={marketing_id}的营销活动不存在', - 'seckill_activity_not_exist_with_id' => 'seckill_id={seckill_id}的秒杀活动不存在', - 'promotion_group_activity_not_exist_with_id' => 'group_id={group_id}的拼团活动不存在', - 'package_not_exist_with_id' => 'package_id={package_id}的组合商品不存在', - 'point_activity_not_exist_with_id' => 'activity_id={activity_id}的积分活动不存在', - 'user_task_activity_not_exist_with_id' => 'activity_id={activity_id}的用户任务活动不存在', - 'user_signin_rule_not_exist_with_id' => 'activity_id={activity_id}的用户签到规则不存在', - 'turntable_activity_not_exist_with_id' => 'activity_id={activity_id}的转盘活动不存在', - 'specific_crowd_discount_not_exist_with_id' => 'discount_id={discount_id}的特定人群优惠不存在', - 'user_bargain_activity_not_exist' => '您参加的bargain_id={bargain_id}的砍价活动不存在', + 'bargain_activity_not_exist_with_id' => 'bargain_id=:bargain_id的砍价活动不存在', + 'bargain_activity_delete_not_exist_with_id' => 'bargain_id=:bargain_id的助力活动不存在', + 'marketing_activity_not_exist_with_id' => 'marketing_id=:marketing_id的营销活动不存在', + 'seckill_activity_not_exist_with_id' => 'seckill_id=:seckill_id的秒杀活动不存在', + 'promotion_group_activity_not_exist_with_id' => 'group_id=:group_id的拼团活动不存在', + 'package_not_exist_with_id' => 'package_id=:package_id的组合商品不存在', + 'point_activity_not_exist_with_id' => 'activity_id=:activity_id的积分活动不存在', + 'user_task_activity_not_exist_with_id' => 'activity_id=:activity_id的用户任务活动不存在', + 'user_signin_rule_not_exist_with_id' => 'activity_id=:activity_id的用户签到规则不存在', + 'turntable_activity_not_exist_with_id' => 'activity_id=:activity_id的转盘活动不存在', + 'specific_crowd_discount_not_exist_with_id' => 'discount_id=:discount_id的特定人群优惠不存在', + 'user_bargain_activity_not_exist' => '您参加的bargain_id=:bargain_id的砍价活动不存在', // Services错误消息 - 'activity_not_exist_with_id' => '错误,id为:{id} 的活动不存在', + 'activity_not_exist_with_id' => '错误,id为::id 的活动不存在', 'activity_not_exist_or_wrong_id' => '错误,活动不存在或id错误', 'turntable_activity_not_enabled' => '转盘活动未开启', 'not_in_activity_time' => '不在活动时间内', @@ -189,11 +189,11 @@ return [ 'draw_activity_not_started' => '抽奖活动未开始', 'insufficient_user_points' => '用户积分不足', 'draw_times_reach_activity_limit' => '抽奖次数达到活动上限制', - 'daily_sms_limit_reached' => '今日发送短信次数已达{max_times}次', + 'daily_sms_limit_reached' => '今日发送短信次数已达:max_times次', 'register_title_required' => '注册标题必填', 'please_select_ad_image' => '请选择广告图', 'please_select_distributor' => '请选择分销商', - 'bargain_activity_not_exist_with_bargain_id' => 'bargain_id为{bargain_id}的砍价活动不存在!', + 'bargain_activity_not_exist_with_bargain_id' => 'bargain_id为:bargain_id的砍价活动不存在!', 'please_select_specific_gift_date' => '请选择具体赠送的日期', 'please_select_date' => '请选择日期', 'activity_start_time_cannot_greater_than_end_time' => '活动开始时间不能大于结束时间', @@ -214,7 +214,7 @@ return [ 'please_select_promotion_area' => '请选择推广区域', 'sms_template_format_error' => '短信模版格式错误,检测不到变量', 'sms_template_variables_too_many' => '短信模版变量过多,最多支持20个变量', - 'sms_template_variable_length_error' => '短信模版变量长度超限制:{variable_name}', + 'sms_template_variable_length_error' => '短信模版变量长度超限制::variable_name', 'promotion_activity_time_conflict' => '您选择的时间范围内已存在营销活动', 'activity_not_exist_error' => '错误,活动不存在', 'points_task_not_exist_error' => '错误,积分任务不存在', @@ -308,11 +308,11 @@ return [ 'applicable_platform_required' => '适用平台必填', 'regular_crossborder_cannot_package' => '普通商品和跨境商品不能作为组合商品售卖', 'activity_start_time_cannot_greater_than_publish' => '活动开始时间不能大于活动发布时间', - 'product_stock_required_greater_than_zero' => '商品{item_title}的库存必填,并且必须大于0', - 'product_price_required_greater_than_zero' => '商品{item_title}的价格必填,并且必须大于0', - 'product_limit_required_greater_than_zero' => '商品{item_title}的每人限购必填,并且必须大于0', + 'product_stock_required_greater_than_zero' => '商品:item_title的库存必填,并且必须大于0', + 'product_price_required_greater_than_zero' => '商品:item_title的价格必填,并且必须大于0', + 'product_limit_required_greater_than_zero' => '商品:item_title的每人限购必填,并且必须大于0', 'current_activity_not_editable' => '当前活动不可编辑', - 'store_has_valid_activity_same_time' => '店铺id={id}在同时段已存在有效活动', + 'store_has_valid_activity_same_time' => '店铺id=:id在同时段已存在有效活动', 'import_file_unrecognizable' => '导入文件无法识别', 'error_rows_too_many_show_100' => '错误行数过多,系统仅显示前100行。', 'signature_not_set_cannot_send_sms' => '签名未设置,不能发送短信', @@ -342,7 +342,7 @@ return [ 'please_select_main_category' => '请选择主分类', 'please_select_tags' => '请选择标签', 'please_select_brand' => '请选择品牌', - 'product_inventory_insufficient' => '商品{item_name}库存不足!', + 'product_inventory_insufficient' => '商品:item_name库存不足!', // 拼团活动相关错误消息 'invalid_product' => '无效商品', @@ -363,7 +363,7 @@ return [ 'end_time_greater_than_start' => '结束时间要大于开始时间', 'product_not_found' => '没有找到该商品', 'group_price_cannot_greater_than_sale_price' => '拼团价格不能大于商品的销售价格,请检查后再提交!', - 'group_price_cannot_greater_than_store_price' => '拼团价格不能大于店铺(店铺ID:{store_id})的销售价格,请检查后再提交!', + 'group_price_cannot_greater_than_store_price' => '拼团价格不能大于店铺(店铺ID::store_id)的销售价格,请检查后再提交!', // 拼团队伍相关验证 'company_id_required' => '企业id必填', diff --git a/resources/lang/zh-CN/SelfserviceBundle.php b/resources/lang/zh-CN/SelfserviceBundle.php index bc60c7c..1f94538 100644 --- a/resources/lang/zh-CN/SelfserviceBundle.php +++ b/resources/lang/zh-CN/SelfserviceBundle.php @@ -7,14 +7,14 @@ return [ // 报名活动相关 'activity_not_exist' => '活动不存在', - 'parameter_error' => '参数错误:{status}', + 'parameter_error' => '参数错误::status', 'only_members_can_register' => '只有会员才可以参与报名', 'please_specify_registration_activity' => '请指定报名活动', 'activity_too_popular_try_later' => '活动太火爆了,请稍后再试', 'activity_too_popular_try_later_short' => '活动太火爆,请稍后再试', 'registration_data_cannot_empty' => '报名数据不能为空', - 'field_required' => '{field_title}必填', - 'field_required_with_card' => '{card_title}下的{field_title}必填', + 'field_required' => ':field_title必填', + 'field_required_with_card' => ':card_title下的:field_title必填', 'please_enter_correct_mobile' => '请填写正确的手机号', 'activity_registration_not_allow_modify' => '活动报名不允许修改', 'please_fill_registration_form' => '请填写报名表单', @@ -90,9 +90,9 @@ return [ // 其他服务错误消息 'data_error' => '数据有误', - 'field_required_simple' => '{field_title}必填', - 'field_must_be_number' => '{field_title}必须是数字', - 'activity_group_code_error' => '活动分组编码错误:{group_no}', + 'field_required_simple' => ':field_title必填', + 'field_must_be_number' => ':field_title必须是数字', + 'activity_group_code_error' => '活动分组编码错误::group_no', // checkActivityValid方法错误消息 'activity_not_exist_err' => '活动不存在', diff --git a/routes/api/distributor.php b/routes/api/distributor.php index 14569ae..50178d5 100644 --- a/routes/api/distributor.php +++ b/routes/api/distributor.php @@ -18,6 +18,7 @@ $api->version('v1', function($api) { $api->get('/distributors', ['name' => '获取店铺列表','middleware'=>['activated', 'datapass'], 'as' => 'distributor.list', 'uses'=>'Distributor@getDistributorList']); $api->get('/distributors/info', ['name' => '获取指定店铺信息','middleware'=>['activated','datapass'], 'as' => 'distributor.info', 'uses'=>'Distributor@getDistributorInfo']); $api->put('/distributor/{distributor_id}', ['name' => '更新店铺','middleware'=>'activated', 'as' => 'distributor.edit', 'uses'=>'Distributor@updateDistributor']); + $api->put('/distributor/{distributor_id}/payment-subject', ['name' => '设置店铺收款主体','middleware'=>'activated', 'as' => 'distributor.payment.subject.set', 'uses'=>'Distributor@setPaymentSubject']); $api->get('/distributor/count/{distributorId}', ['name' => '获取店铺统计','middleware'=>'activated', 'as' => 'front.wxapp.distributor.count', 'uses'=>'Distributor@getDistributorCount']); $api->get('/distributor/wxacode', ['name' => '获取店铺小程序码','middleware'=>'activated', 'as' => 'distributor.wxacode', 'uses'=>'Distributor@getWxaDistributorCodeStream']); diff --git a/routes/api/trade.php b/routes/api/trade.php index eddfdbc..4e3d0d5 100644 --- a/routes/api/trade.php +++ b/routes/api/trade.php @@ -119,6 +119,7 @@ $api->version('v1', function($api) { $api->group(['namespace' => 'PaymentBundle\Http\Api\V1\Action', 'middleware' => ['api.auth','shoplog'], 'providers' => 'jwt'], function($api) { $api->post('/trade/payment/setting', [ 'name'=>'支付配置信息保存','middleware'=>'activated', 'as' => 'trade.payment.setting.set', 'uses'=>'Payment@setPaymentSetting']); $api->get('/trade/payment/setting', [ 'name'=>'获取支付配置信息','middleware'=>'activated', 'as' => 'trade.payment.setting.get', 'uses'=>'Payment@getPaymentSetting']); + $api->get('/trade/payment/open-status', [ 'name'=>'获取支付配置开关状态','middleware'=>'activated', 'as' => 'trade.payment.open.status.get', 'uses'=>'Payment@getPaymentOpenStatus']); $api->get('/trade/payment/list', [ 'name'=>'获取支付配置信息列表','middleware'=>'activated', 'as' => 'trade.payment.setting.list', 'uses'=>'Payment@getPaymentSettingList']); $api->get('/trade/payment/hfpayversionstatus', [ 'name'=>'获取汇付天下版本状态','middleware'=>'activated', 'as' => 'trade.payment.hfpay.status', 'uses'=>'Payment@getHfpayVersionStatus']); $api->get('/trade/payment/rsakey', [ 'name'=>'生成RSA密钥','middleware'=>'activated', 'as' => 'trade.payment.rsa.gen', 'uses'=>'Payment@genRsaKey']); diff --git a/src/AftersalesBundle/Http/Api/V1/Action/Refund.php b/src/AftersalesBundle/Http/Api/V1/Action/Refund.php index 33aec41..284166c 100644 --- a/src/AftersalesBundle/Http/Api/V1/Action/Refund.php +++ b/src/AftersalesBundle/Http/Api/V1/Action/Refund.php @@ -412,6 +412,26 @@ class Refund extends Controller $filter['company_id'] = app('auth')->user()->get('company_id'); $merchantId = app('auth')->user()->get('merchant_id'); $operatorType = app('auth')->user()->get('operator_type'); + + // 处理供应商端权限 + if ($operatorType == 'supplier') { + $filter['supplier_id'] = app('auth')->user()->get('operator_id'); + } + + // 处理店铺端权限 + $distributorListSet = app('auth')->user()->get('distributor_ids'); + if (!empty($distributorListSet)) { + $distributorIdSet = array_column($distributorListSet, 'distributor_id'); + if (isset($filter['distributor_id']) && $filter['distributor_id']) { + if (!in_array($filter['distributor_id'], $distributorIdSet)) { + unset($filter['distributor_id']); + } + } else { + $filter['distributor_id'] = $distributorIdSet; + } + } + + // 处理商家端权限 if ($operatorType == 'merchant') { $filter['merchant_id'] = $merchantId; } diff --git a/src/CompanysBundle/Ego/CompanysActivationEgo.php b/src/CompanysBundle/Ego/CompanysActivationEgo.php index 7e04dea..f7af6a7 100644 --- a/src/CompanysBundle/Ego/CompanysActivationEgo.php +++ b/src/CompanysBundle/Ego/CompanysActivationEgo.php @@ -690,6 +690,10 @@ class CompanysActivationEgo //验证资源包的有效性 private function checkValid($companyId) { + $data['expired_at'] = strtotime('2037-01-01'); + $data['desc'] = '开源版本'; + $data['valid'] = 'true'; + return $data; $redisKey = "AuthorizeActivation:". sha1($companyId); $datalist = app('redis')->connection('companys')->Hgetall($redisKey); diff --git a/src/CompanysBundle/Ego/UpgradeEgo.php b/src/CompanysBundle/Ego/UpgradeEgo.php index 9e6733c..a80c141 100644 --- a/src/CompanysBundle/Ego/UpgradeEgo.php +++ b/src/CompanysBundle/Ego/UpgradeEgo.php @@ -709,6 +709,7 @@ class UpgradeEgo */ public function getSwooleLicense() { + return ['Product_type'=>'ECSHOPX_OPENSOURCE']; // return ['Product_type'=>'ECSHOPX2_FREE']; if (!function_exists('swoole_get_license')) { throw new \Exception('请确认swoole_loader扩展已正确安装!'); diff --git a/src/CompanysBundle/Http/Api/V1/Action/Companys.php b/src/CompanysBundle/Http/Api/V1/Action/Companys.php index 99f6fcd..6d0073d 100644 --- a/src/CompanysBundle/Http/Api/V1/Action/Companys.php +++ b/src/CompanysBundle/Http/Api/V1/Action/Companys.php @@ -279,6 +279,7 @@ class Companys extends BaseController $result['redis_version'] = app('redis')->getProfile()->getVersion(); // 检查license有效期 $result['license']['show_expier_tip'] = 0; + /** if (extension_loaded('swoole_loader')) { $license = swoole_get_license(); $license = reset($license); @@ -290,7 +291,7 @@ class Companys extends BaseController } } } - + **/ return $this->response->array($result); } diff --git a/src/CompanysBundle/Http/Api/V1/Action/WxExternalConfigController.php b/src/CompanysBundle/Http/Api/V1/Action/WxExternalConfigController.php index ee30356..077c9f8 100644 --- a/src/CompanysBundle/Http/Api/V1/Action/WxExternalConfigController.php +++ b/src/CompanysBundle/Http/Api/V1/Action/WxExternalConfigController.php @@ -206,9 +206,10 @@ class WxExternalConfigController extends BaseController * @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/CompanysErrorRespones") ) ) * ) */ - public function updateWxExternalConfig(Request $request) + public function updateWxExternalConfig(Request $request, $wx_external_config_id) { - $params = $request->all('wx_external_config_id', 'app_desc', 'app_name', 'app_id'); + $params = $request->all('app_desc', 'app_name', 'app_id'); + $params['wx_external_config_id'] = $wx_external_config_id; $rules = [ 'wx_external_config_id' => ['required', '请填写配置ID'], 'app_name' => ['required', '请填写小程序名称'], @@ -310,15 +311,15 @@ class WxExternalConfigController extends BaseController * @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/CompanysErrorRespones") ) ) * ) */ - public function deleteWxExternalConfig(Request $request, $wxExternalConfigId) + public function deleteWxExternalConfig(Request $request, $wx_external_config_id) { - if (intval($wxExternalConfigId) <= 0) { + if (intval($wx_external_config_id) <= 0) { throw new ResourceException('配置不存在'); } $companyId = app('auth')->user()->get('company_id'); - $result = $this->wxExternalConfig->deleteWxExternalConfig($companyId, intval($wxExternalConfigId)); + $result = $this->wxExternalConfig->deleteWxExternalConfig($companyId, intval($wx_external_config_id)); return $this->response->array(['status' => $result]); } diff --git a/src/CompanysBundle/MultiLang/MultiLangItem.php b/src/CompanysBundle/MultiLang/MultiLangItem.php index d50530d..8fe94b8 100644 --- a/src/CompanysBundle/MultiLang/MultiLangItem.php +++ b/src/CompanysBundle/MultiLang/MultiLangItem.php @@ -232,8 +232,119 @@ CREATE TABLE {$table} LIKE `multi_lang_mod`; $type = is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR; $stmt->bindValue($key, $val, $type); } - return $stmt->executeQuery()->fetchAllAssociative(); + $result = $stmt->executeQuery()->fetchAllAssociative(); + return $result ? $result : []; } + public function getOneByFilter(array $filter = []): array + { + $table = $this->table; + $whereData = $this->_filter($filter); + $whereClauses = $whereData['whereClauses']; + $params = $whereData['params']; + // 构造 SQL + $sql = "SELECT * FROM {$table}"; + if (!empty($whereClauses)) { + $sql .= ' WHERE ' . implode(' AND ', $whereClauses); + } + + $conn = app("registry")->getConnection("default"); + $stmt = $conn->prepare($sql); + foreach ($params as $key => $val) { + $type = is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR; + $stmt->bindValue($key, $val, $type); + } + $result = $stmt->executeQuery()->fetchAssociative(); + return $result ? $result : []; + } + + public function deleteBy(array $filter) + { + $table = $this->table; + $whereData = $this->_filter($filter); + $whereClauses = $whereData['whereClauses']; + $params = $whereData['params']; + // 构造sql + $sql = "DELETE FROM {$table}"; + if (!empty($whereClauses)) { + $sql .= ' WHERE ' . implode(' AND ', $whereClauses); + } + $conn = app("registry")->getConnection("default"); + $stmt = $conn->prepare($sql); + foreach ($params as $key => $val) { + $type = is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR; + $stmt->bindValue($key, $val, $type); + } + + return $stmt->executeQuery()->fetchAssociative(); + } + + private function _filter($filter) + { + $whereClauses = []; + $params = []; + // 构造 WHERE 语句(与前面 findByFilter 相同逻辑) + foreach ($filter as $rawKey => $value) { + if(is_array($value)){ + if (strpos($rawKey, '|') === false) { + $rawKey .= '|in'; + } + } + [$field, $operator] = explode('|', $rawKey) + [null, 'eq']; + $paramKey = 'param_' . uniqid($field . '_', false); + + switch ($operator) { + case 'eq': + case '': + $whereClauses[] = "`$field` = :$paramKey"; + $params[$paramKey] = $value; + break; + case 'lt': + $whereClauses[] = "`$field` < :$paramKey"; + $params[$paramKey] = $value; + break; + case 'lte': + $whereClauses[] = "`$field` <= :$paramKey"; + $params[$paramKey] = $value; + break; + case 'gt': + $whereClauses[] = "`$field` > :$paramKey"; + $params[$paramKey] = $value; + break; + case 'gte': + $whereClauses[] = "`$field` >= :$paramKey"; + $params[$paramKey] = $value; + break; + case 'neq': + $whereClauses[] = "`$field` != :$paramKey"; + $params[$paramKey] = $value; + break; + case 'contains': + $whereClauses[] = "`$field` LIKE :$paramKey"; + $params[$paramKey] = '%' . $value . '%'; + break; + case 'in': + if (!is_array($value) || empty($value)) { + break; + } + $inParams = []; + foreach ($value as $i => $v) { + $inKey = "{$paramKey}_{$i}"; + $inParams[] = ":$inKey"; + $params[$inKey] = $v; + } + $whereClauses[] = "`$field` IN (" . implode(', ', $inParams) . ")"; + break; + case 'null': + $whereClauses[] = "`$field` IS NULL"; + break; + case 'notnull': + $whereClauses[] = "`$field` IS NOT NULL"; + break; + } + } + + return ['whereClauses' => $whereClauses, 'params' => $params]; + } } diff --git a/src/CompanysBundle/Repositories/OperatorsRepository.php b/src/CompanysBundle/Repositories/OperatorsRepository.php index 486d6ba..52dfc48 100644 --- a/src/CompanysBundle/Repositories/OperatorsRepository.php +++ b/src/CompanysBundle/Repositories/OperatorsRepository.php @@ -28,7 +28,7 @@ class OperatorsRepository extends EntityRepository public $module = 'operators'; // 多语言对应的模块 public $primaryKey = 'operator_id'; // 主键,对应data_id public $langField = [ - 'login_name','username','contact','split_ledger_info' + 'username','contact','split_ledger_info' ]; // 多语言字段 public function getEntity() diff --git a/src/CompanysBundle/Services/AuthService.php b/src/CompanysBundle/Services/AuthService.php index cabc41d..92cebd2 100644 --- a/src/CompanysBundle/Services/AuthService.php +++ b/src/CompanysBundle/Services/AuthService.php @@ -230,7 +230,7 @@ class AuthService } // 原有逻辑:通过手机号或login_name查询 - if (preg_match("/^1[3456789]{1}\d{9}$/", $params['username'])) { + if (preg_match("/^1[23456789]{1}\d{9}$/", $params['username'])) { $filter['mobile'] = $params['username']; } else { $filter['login_name'] = $params['username']; diff --git a/src/CompanysBundle/Services/CommonLangModService.php b/src/CompanysBundle/Services/CommonLangModService.php index defc299..9cb6bb1 100644 --- a/src/CompanysBundle/Services/CommonLangModService.php +++ b/src/CompanysBundle/Services/CommonLangModService.php @@ -18,6 +18,7 @@ namespace CompanysBundle\Services; use Dingo\Api\Exception\ResourceException; +use CompanysBundle\MultiLang\MultiLangItem; use GoodsBundle\Services\MultiLang\MagicLangTrait; class CommonLangModService @@ -28,46 +29,32 @@ class CommonLangModService private $repository = []; // 多语言字段后缀 private $suffix = '_lang'; - public $totalLang = [ - 'zh-CN' => '\CompanysBundle\Entities\CommonLangModCN', - 'en-CN' => '\CompanysBundle\Entities\CommonLangModEN', - 'ar-SA' => '\CompanysBundle\Entities\CommonLangModAR', - ]; + + public $totalLang = []; public function __construct() { - $this->setLangMapRepository(); - } - - private function setLangMapRepository() - { - if (empty($this->totalLang)) { - throw new ResourceException("不存在的多语言totalLang"); + $config = config('langue'); + if (empty($config)) { + throw new ResourceException("不存在的多语言配置,请去config/langue.php配置"); } - foreach ($this->totalLang as $lang => $className) { - $this->repository[$lang] = app('registry')->getManager('default')->getRepository($className); - } - - return true; + $this->totalLang = $config; } - + public function getLangMapRepository($langue = 'zh') { - if (empty($this->repository)) { - $this->setLangMapRepository(); - } - $classObj = $this->repository[$langue] ?? null; - if (empty($classObj)) { - throw new ResourceException("不存在的多语言Repository:{$langue}"); + $service = new MultiLangItem($langue, 'other'); + if (empty($service)) { + throw new ResourceException("不存在的多语言service:{$langue}"); } - return $classObj; + return $service; } - + // 获取多语言字段 public function getFieldByLangue($company_id, $langue, $field, $data_id, $table, $module) { - $classObj = $this->getLangMapRepository($langue); + $repository = $this->getLangMapRepository($langue); $filter = [ 'company_id' => $company_id, 'table_name' => $table, @@ -76,31 +63,31 @@ class CommonLangModService 'data_id' => $data_id, 'lang' => $langue, ]; - $info = $classObj->getInfo($filter); + $info = $repository->getOneByFilter($filter); return $info['attribute_value'] ?? ''; } - public function updateDataIdByLangue($company_id, $langue, $table, $module, $data_id, $new_data_id) - { - $classObj = $this->getLangMapRepository($langue); + public function updateDataIdByLangue($company_id, $langue, $table, $module, $data_id, $new_data_id) + { + $repository = $this->getLangMapRepository($langue); $filter = [ 'company_id' => $company_id, 'table_name' => $table, 'module_name' => $module, 'data_id' => $data_id, ]; - $info = $classObj->getInfo($filter); + $info = $repository->getOneByFilter($filter); if (empty($info)) { return false; } - $res = $classObj->updateOneBy( $filter, + $res = $repository->updateByFilter( $filter, [ 'data_id' => $new_data_id ]); return $res ?? false; - } + } // 获取参数中的多语言字段 public function getParamsLang($repository, $data) @@ -206,16 +193,16 @@ class CommonLangModService $lang = $this->getLang(); } foreach ($langBag as $k => $v) { - // $field = str_replace($this->suffix, "", $k); - // foreach ($v as $lang => $vv){ - $insertData = $baseInsertData; - $insertData['lang'] = $lang; - $insertData['attribute_value'] = $v; - $insertData['field'] = $k; - $insertData['data_id'] = $id; - $repository = $this->getLangMapRepository($lang); - $repository->create($insertData); - // } + $insertData = $baseInsertData; + $insertData['lang'] = $lang; + $insertData['attribute_value'] = $v; + $insertData['field'] = $k; + $insertData['data_id'] = $id; + $insertData['created'] = time(); + $insertData['updated'] = time(); + $repository = $this->getLangMapRepository($lang); + // $repository->create($insertData); + $repository->insert($insertData); } return true; @@ -235,6 +222,7 @@ class CommonLangModService $v = is_array($v) ? json_encode($v) : $v; $updateData = [ 'attribute_value' => $v, + 'updated' => time(), ]; $filter = [ 'company_id' => $companyId, @@ -245,7 +233,8 @@ class CommonLangModService 'lang'=> $lang, ]; $repository = $this->getLangMapRepository($lang); - $info = $repository->getInfo($filter); + // $info = $repository->getInfo($filter); + $info = $repository->getOneByFilter($filter); if (empty($info)) { $baseInsertData = [ @@ -259,9 +248,13 @@ class CommonLangModService $insertData['attribute_value'] = $v; $insertData['field'] = $k; $insertData['data_id'] = $dataId; - $repository->create($insertData); + $insertData['created'] = time(); + $insertData['updated'] = time(); + // $repository->create($insertData); + $repository->insert($insertData); }else{ - $repository->updateOneBy($filter,$updateData); + // $repository->updateOneBy($filter,$updateData); + $repository->updateByFilter($filter,$updateData); } } @@ -270,31 +263,33 @@ class CommonLangModService public function deleteLang(int $companyId, string $tableName, int $dataId, string $module) { - // foreach ($this->totalLang as $lang => $className) { - $lang = $this->getLang(); - $repository = $this->getLangMapRepository($lang); - $filter = [ - 'company_id' => $companyId, - 'table_name'=> $tableName, - 'module_name' => $module, - 'data_id'=> $dataId, - ]; - $repository->deleteBy($filter); - // } + $lang = $this->getLang(); + $repository = $this->getLangMapRepository($lang); + $filter = [ + 'company_id' => $companyId, + 'table_name'=> $tableName, + 'module_name' => $module, + 'data_id'=> $dataId, + ]; + $repository->deleteBy($filter); return true; } public function filterByLang(string $lang, string $field, string $content, string $tableName) { + // 处理带操作符的字段名,如 page_name|contains,只取字段名部分 + $fieldParts = explode('|', $field); + $fieldName = $fieldParts[0]; + $filter = [ 'lang'=>$lang, - 'field'=>$field, + 'field'=>$fieldName, 'table_name'=>$tableName, 'attribute_value|contains'=>$content, ]; $repository = $this->getLangMapRepository($lang); - $list = $repository->getLists($filter,'*', -1, -1); + $list = $repository->getListByFilter($filter, -1, -1); if(empty($list)){ return []; } @@ -324,7 +319,7 @@ class CommonLangModService if(empty($id)){ return $body; } - $totalLang = array_keys($this->totalLang); + $totalLang = $this->totalLang; $langMap = []; $fieldsArr = $this->fieldHandle($fields); $fields = $fieldsArr['fields']; @@ -335,7 +330,10 @@ class CommonLangModService $filter['module_name'] = $module; } $repository = $this->getLangMapRepository($lang); - $content = $repository->getLists($filter, '*', 1, -1); + $content = $repository->getListByFilter($filter, -1, -1); + if(empty($content)){ + continue; + } // 过滤数据字段 foreach($content as $k => $v){ if(isset($fieldsOpts[$v['field']]) && !empty($fieldsOpts[$v['field']])){ @@ -375,7 +373,7 @@ class CommonLangModService if(empty($ids)){ return $dataList; } - $totalLang = array_keys($this->totalLang); + $totalLang = $this->totalLang; $langMap = []; $fieldsArr = $this->fieldHandle($fields); $fields = $fieldsArr['fields']; @@ -383,7 +381,10 @@ class CommonLangModService foreach($totalLang as $lang) { $filter = ['table_name' => $tableName, 'field' => $fields, 'lang' => $lang, 'data_id'=>$ids]; $repository = $this->getLangMapRepository($lang); - $listTmp = $repository->getLists($filter, '*', 1, -1); + $listTmp = $repository->getListByFilter($filter, -1, -1); + if(empty($listTmp)){ + continue; + } // 过滤数据字段 foreach($listTmp as $k => $v){ if(isset($fieldsOpts[$v['field']]) && !empty($fieldsOpts[$v['field']])){ @@ -442,16 +443,7 @@ class CommonLangModService if (!empty($langBag)) { $resultLang = []; $langue = $this->getLang(); - foreach($this->totalLang as $lang => $val) { - if ($lang != $langue) { - continue; - } - // $mergeData = []; - // foreach($langBag as $k => $v) { - // $mergeData[$k] = $v[$lang]; - // } - $resultLang[$lang] = array_merge($oldData, $langBag); - } + $resultLang[$langue] = array_merge($oldData, $langBag); } return !empty($resultLang) ? $resultLang : $oldData; diff --git a/src/CompanysBundle/Services/RepositoryInterceptor.php b/src/CompanysBundle/Services/RepositoryInterceptor.php index c0ba8ef..6c3079f 100644 --- a/src/CompanysBundle/Services/RepositoryInterceptor.php +++ b/src/CompanysBundle/Services/RepositoryInterceptor.php @@ -291,16 +291,21 @@ class RepositoryInterceptor $lang = $ns->getLang(); $prkFilter = $filter[$prk] ?? ''; // 所有过滤字段keys foreach ($filter as $key => $value) { + $dataIdArr = ''; // 必须是多语言字段 - if (in_array($key, $fieldLangue)) { + // 可能存在xx|xx 这种数据, 所以要兼容 + $filterkeys = explode('|', $key); + if (in_array($filterkeys[0], $fieldLangue)) { $dataIdArr = $ns->filterByLang($lang, $key, $value, $table); - } - // 如果存在多语言字段主键,说明可能其他地方使用了主键过滤,我们需要合并掉 - if (!empty($dataIdArr)) { - if (!empty($prkFilter)) { - $filter[$key] = array_merge($filter[$key], $dataIdArr); - }else{ - $filter[$key] = $dataIdArr; + // 如果存在多语言字段主键,说明可能其他地方使用了主键过滤,我们需要合并掉 + if (!empty($dataIdArr)) { + if (!empty($prkFilter)) { + $filter[$prk] = array_merge((array)$prkFilter, $dataIdArr); + }else{ + $filter[$prk] = $dataIdArr; + } + // 移除多语言字段的原始过滤条件,因为已经转换为按主键过滤 + unset($filter[$key]); } } } diff --git a/src/DistributionBundle/Entities/Distributor.php b/src/DistributionBundle/Entities/Distributor.php index fa31039..a5bc7f3 100644 --- a/src/DistributionBundle/Entities/Distributor.php +++ b/src/DistributionBundle/Entities/Distributor.php @@ -506,6 +506,13 @@ class Distributor */ private $jst_shop_id = 0; + /** + * @var integer + * + * @ORM\Column(name="payment_subject", type="smallint", options={"comment":"收款主体,0=平台,1=店铺", "default": 0}) + */ + private $payment_subject = 0; + public function setIsRefundFreight($isRefundFreight) { $this->is_refund_freight = $isRefundFreight; @@ -2053,4 +2060,26 @@ class Distributor { $this->open_divided = $open_divided; } + + /** + * Set payment_subject + * + * @param integer $paymentSubject + * @return Distributor + */ + public function setPaymentSubject($paymentSubject) + { + $this->payment_subject = $paymentSubject; + return $this; + } + + /** + * Get payment_subject + * + * @return integer + */ + public function getPaymentSubject() + { + return $this->payment_subject; + } } diff --git a/src/DistributionBundle/Http/Api/V1/Action/Distributor.php b/src/DistributionBundle/Http/Api/V1/Action/Distributor.php index 79111cf..760de83 100644 --- a/src/DistributionBundle/Http/Api/V1/Action/Distributor.php +++ b/src/DistributionBundle/Http/Api/V1/Action/Distributor.php @@ -1118,6 +1118,14 @@ class Distributor extends Controller if (!is_null($distributionType) && $distributionType != '') { $filter['distribution_type'] = $request->input('distribution_type'); } + + // 收款主体筛选 + if ($request->input('payment_subject') !== null) { + $paymentSubject = $request->input('payment_subject'); + if (in_array($paymentSubject, [0, 1])) { + $filter['payment_subject'] = $paymentSubject; + } + } if ($operatorType == 'merchant' || $operatorType == 'distributor') { unset($filter['distribution_type']); } @@ -1242,6 +1250,43 @@ class Distributor extends Controller return $this->response->array($data); } + /** + * @SWG\Put( + * path="/distributor/{distributor_id}/payment-subject", + * summary="设置店铺收款主体", + * tags={"店铺"}, + * description="设置店铺收款主体", + * operationId="setDistributorPaymentSubject", + * @SWG\Parameter( name="Authorization", in="header", description="JWT验证token", required=true, type="string"), + * @SWG\Parameter( name="distributor_id", in="path", description="店铺ID", required=true, type="integer"), + * @SWG\Parameter( name="payment_subject", in="formData", description="收款主体,0=平台,1=店铺", required=true, type="integer"), + * @SWG\Response( + * response=200, + * description="成功返回结构", + * @SWG\Schema( + * @SWG\Property(property="status", type="boolean", example=true), + * ), + * ), + * @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/ErrorResponse") ) ) + * ) + */ + public function setPaymentSubject(Request $request, $distributor_id) + { + $companyId = app('auth')->user()->get('company_id'); + $paymentSubject = $request->input('payment_subject'); + + // 参数验证 + if (!in_array($paymentSubject, [0, 1])) { + throw new ResourceException('payment_subject参数错误,只能为0(平台)或1(店铺)'); + } + + // 调用Service处理业务逻辑 + $distributorService = new DistributorService(); + $distributorService->setPaymentSubject($companyId, $distributor_id, $paymentSubject); + + return $this->response->array(['status' => true]); + } + /** * @SWG\Get( * path="/distributor/count/{distributorId}", diff --git a/src/DistributionBundle/Http/Api/V1/Action/DistributorShopController.php b/src/DistributionBundle/Http/Api/V1/Action/DistributorShopController.php index bcc62d6..5c02def 100644 --- a/src/DistributionBundle/Http/Api/V1/Action/DistributorShopController.php +++ b/src/DistributionBundle/Http/Api/V1/Action/DistributorShopController.php @@ -25,6 +25,7 @@ use DistributionBundle\Services\DistributorTagsService; use Dingo\Api\Exception\ResourceException; use Dingo\Api\Exception\StoreResourceFailedException; use Exception; +use ThirdPartyBundle\Services\Map\MapService; class DistributorShopController extends Controller { @@ -765,7 +766,19 @@ class DistributorShopController extends Controller if (!$address) { throw new ResourceException(trans('DistributionBundle/Controllers/Distributor.address_required'), 400); } - $area = get_latlng_by_address($address); + + // 获取公司ID,与UploadDistributor保持一致 + $companyId = app('auth')->user()->get('company_id'); + + // 使用MapService::make($companyId)获取实例,这样会优先使用数据库配置,与UploadDistributor保持一致 + $mapService = MapService::make($companyId); + + // 调用getLatAndLngByPosition方法获取原始响应(与get_latlng_by_address返回格式一致) + // 传入空region,完整地址作为address + $area = $mapService->getThirdPartyMapService()->getLatAndLngByPosition([ + "address" => (string)$address + ]); + return $this->response->array($area); } diff --git a/src/DistributionBundle/Repositories/DistributorRepository.php b/src/DistributionBundle/Repositories/DistributorRepository.php index 0a724f6..3f539cb 100644 --- a/src/DistributionBundle/Repositories/DistributorRepository.php +++ b/src/DistributionBundle/Repositories/DistributorRepository.php @@ -113,6 +113,7 @@ class DistributorRepository extends EntityRepository 'jst_shop_id', 'kuaizhen_store_id', 'open_divided',//开启店铺隔离 + 'payment_subject', // 收款主体 ]; public function getLangService() @@ -176,7 +177,15 @@ class DistributorRepository extends EntityRepository } if (isset($data['auto_sync_goods'])) { - $data['auto_sync_goods'] = $data['auto_sync_goods'] == 'true' ? 1 : 0; + // 兼容多种输入格式:字符串 'true'/'false',整数 1/0,布尔值 true/false + if (is_string($data['auto_sync_goods'])) { + $data['auto_sync_goods'] = ($data['auto_sync_goods'] == 'true' || $data['auto_sync_goods'] === '1') ? 1 : 0; + } elseif (is_bool($data['auto_sync_goods'])) { + $data['auto_sync_goods'] = $data['auto_sync_goods'] ? 1 : 0; + } else { + // 整数类型,直接转换为 0 或 1 + $data['auto_sync_goods'] = (int)$data['auto_sync_goods'] ? 1 : 0; + } } $entity = $this->findOneBy($filter); @@ -213,7 +222,15 @@ class DistributorRepository extends EntityRepository } if (isset($data['auto_sync_goods'])) { - $data['auto_sync_goods'] = $data['auto_sync_goods'] == 'true' ? 1 : 0; + // 兼容多种输入格式:字符串 'true'/'false',整数 1/0,布尔值 true/false + if (is_string($data['auto_sync_goods'])) { + $data['auto_sync_goods'] = ($data['auto_sync_goods'] == 'true' || $data['auto_sync_goods'] === '1') ? 1 : 0; + } elseif (is_bool($data['auto_sync_goods'])) { + $data['auto_sync_goods'] = $data['auto_sync_goods'] ? 1 : 0; + } else { + // 整数类型,直接转换为 0 或 1 + $data['auto_sync_goods'] = (int)$data['auto_sync_goods'] ? 1 : 0; + } } $conn = app("registry")->getConnection("default"); diff --git a/src/DistributionBundle/Services/DistributorItemsService.php b/src/DistributionBundle/Services/DistributorItemsService.php index f3d1f18..be59190 100644 --- a/src/DistributionBundle/Services/DistributorItemsService.php +++ b/src/DistributionBundle/Services/DistributorItemsService.php @@ -217,18 +217,52 @@ class DistributorItemsService // 店铺商品如果要上架,必须商品池是上架状态 if (isset($params['is_can_sale']) && ($params['is_can_sale'] === true || $params['is_can_sale'] === 'true')) { $itemsService = new ItemsService(); - $_filter = [ - 'company_id' => $params['company_id'], - 'approve_status' => 'instock', - ]; - if (isset($filter['item_id'])) { - $_filter['item_id'] = $filter['item_id']; - }else { - $_filter['goods_id'] = $filter['goods_id']; - } - $itemCount = $itemsService->count($_filter); - if ($itemCount) { - throw new ResourceException("确认商品总部销售状态"); + + if (isset($filter['goods_id'])) { + // 按SPU维度检查:如果goods_id是数组,遍历每个goods_id + // 当其中一个goods_id中的所有item_id都是下架状态,则抛出错误 + $goodsIds = is_array($filter['goods_id']) ? $filter['goods_id'] : [$filter['goods_id']]; + + // 优化:一次性查询所有goods_id下的所有SKU,减少数据库查询次数 + $_filter = [ + 'company_id' => $params['company_id'], + 'goods_id' => $goodsIds, // 直接传数组,支持批量查询 + ]; + $allItems = $itemsService->getItemsList($_filter, 1, -1); + + // 在内存中按goods_id分组统计 + $goodsStats = []; + foreach ($allItems['list'] as $item) { + $goodsId = $item['goods_id']; + if (!isset($goodsStats[$goodsId])) { + $goodsStats[$goodsId] = ['total' => 0, 'instock' => 0]; + } + $goodsStats[$goodsId]['total']++; + if ($item['approve_status'] == 'instock') { + $goodsStats[$goodsId]['instock']++; + } + } + + // 检查每个goods_id:如果全部SKU都是下架状态,抛出错误 + foreach ($goodsIds as $goodsId) { + if (isset($goodsStats[$goodsId]) && $goodsStats[$goodsId]['total'] > 0) { + // 如果该SPU下的所有SKU都是下架状态,抛出错误 + if ($goodsStats[$goodsId]['instock'] == $goodsStats[$goodsId]['total']) { + throw new ResourceException("确认商品总部销售状态"); + } + } + } + } else if (isset($filter['item_id'])) { + // 原逻辑:按单个SKU检查 + $_filter = [ + 'company_id' => $params['company_id'], + 'item_id' => $filter['item_id'], + 'approve_status' => 'instock', + ]; + $itemCount = $itemsService->count($_filter); + if ($itemCount) { + throw new ResourceException("确认商品总部销售状态"); + } } } diff --git a/src/DistributionBundle/Services/DistributorService.php b/src/DistributionBundle/Services/DistributorService.php index 1885b38..dc8f7cb 100644 --- a/src/DistributionBundle/Services/DistributorService.php +++ b/src/DistributionBundle/Services/DistributorService.php @@ -39,6 +39,10 @@ use WechatBundle\Services\OpenPlatform; use OrdersBundle\Traits\GetOrderServiceTrait; use MerchantBundle\Services\MerchantService; +use AftersalesBundle\Services\AftersalesRefundService; +use PaymentBundle\Services\PaymentsService; +use PaymentBundle\Services\Payments\WechatPayService; +use PaymentBundle\Services\Payments\AlipayService; class DistributorService { @@ -433,7 +437,7 @@ class DistributorService } } $distributorInfo = $this->getDefaultDistributor($filter['company_id']); - if ($distributorInfo['is_valid'] === 'false' || $distributorInfo['is_valid'] === false || $distributorInfo['distributor_self'] === 0 || $distributorInfo['distributor_self'] === '0') { + if (!$distributorInfo || $distributorInfo['is_valid'] === 'false' || $distributorInfo['is_valid'] === false || $distributorInfo['distributor_self'] === 0 || $distributorInfo['distributor_self'] === '0') { $distributorInfo = $this->getMainDistributor($filter['company_id']); } @@ -1293,4 +1297,167 @@ class DistributorService } return false; } + + /** + * 设置店铺收款主体 + * + * @param int $companyId 公司ID + * @param int $distributorId 店铺ID + * @param int $paymentSubject 收款主体,0=平台,1=店铺 + * @return bool + * @throws ResourceException + */ + public function setPaymentSubject($companyId, $distributorId, $paymentSubject) + { + // 验证店铺是否存在且属于当前公司 + $distributorInfo = $this->entityRepository->getInfo([ + 'distributor_id' => $distributorId, + 'company_id' => $companyId + ]); + + if (!$distributorInfo) { + throw new ResourceException(trans('DistributionBundle/Services/DistributorService.distributor_not_exists_or_no_permission')); + } + + // 检查店铺下是否有未完成的退款单 + // 需要检查的退款状态:READY(未审核)、AUDIT_SUCCESS(审核成功待退款)、PROCESSING(已发起退款等待到账)、CHANGE(退款异常) + $aftersalesRefundService = new AftersalesRefundService(); + $refundFilter = [ + 'company_id' => $companyId, + 'distributor_id' => $distributorId, + 'refund_status' => ['READY', 'AUDIT_SUCCESS', 'PROCESSING', 'CHANGE'] // 数组形式,Repository会自动使用IN查询 + ]; + // 使用count方法检查是否存在未完成的退款单(性能更好) + $refundCount = $aftersalesRefundService->aftersalesRefundRepository->count($refundFilter); + + if ($refundCount > 0) { + throw new ResourceException(trans('DistributionBundle/Services/DistributorService.has_unfinished_refund_cannot_switch_payment_subject')); + } + + // 支付配置校验 + if ($paymentSubject == 1) { + // 切换为店铺时,需要校验店铺的支付配置 + $this->validateDistributorPaymentConfig($companyId, $distributorId); + } else { + // 切换为平台时,需要校验平台的支付配置 + $this->validatePlatformPaymentConfig($companyId); + } + + // 更新收款主体 + $updateData = ['payment_subject' => $paymentSubject]; + $this->entityRepository->updateBy( + ['distributor_id' => $distributorId, 'company_id' => $companyId], + $updateData + ); + + return true; + } + + /** + * 校验店铺支付配置 + * + * @param int $companyId 公司ID + * @param int $distributorId 店铺ID + * @throws ResourceException + */ + private function validateDistributorPaymentConfig($companyId, $distributorId) + { + $paymentsService = new PaymentsService(); + $paymentStatus = $paymentsService->getPaymentOpenStatusList($companyId); + app('log')->debug('validateDistributorPaymentConfig::paymentStatus====>'.json_encode($paymentStatus, 1)); + $wxpayOpen = $paymentStatus['wxpay']['is_open'] ?? false; + $alipayOpen = $paymentStatus['alipay']['is_open'] ?? false; + + // 检查是否至少有一个支付方式开启 + if (!$wxpayOpen && !$alipayOpen) { + throw new ResourceException(trans('DistributionBundle/Services/DistributorService.switch_to_distributor_payment_subject_need_at_least_one_payment')); + } + + // 检查已开启的支付方式配置是否完整 + if ($wxpayOpen) { + $this->validateWxpayConfig($companyId, $distributorId); + } + + if ($alipayOpen) { + $this->validateAlipayConfig($companyId, $distributorId); + } + } + + /** + * 校验平台支付配置 + * + * @param int $companyId 公司ID + * @throws ResourceException + */ + private function validatePlatformPaymentConfig($companyId) + { + $paymentsService = new PaymentsService(); + $paymentStatus = $paymentsService->getPaymentOpenStatusList($companyId); + app('log')->debug('validatePlatformPaymentConfig::paymentStatus====>'.json_encode($paymentStatus)); + $wxpayOpen = $paymentStatus['wxpay']['is_open'] ?? false; + $alipayOpen = $paymentStatus['alipay']['is_open'] ?? false; + + // 检查已开启的支付方式配置是否完整 + if ($wxpayOpen) { + $this->validateWxpayConfig($companyId, 0); + } + + if ($alipayOpen) { + $this->validateAlipayConfig($companyId, 0); + } + } + + /** + * 校验微信支付配置 + * + * @param int $companyId 公司ID + * @param int $distributorId 店铺ID,0表示平台 + * @throws ResourceException + */ + private function validateWxpayConfig($companyId, $distributorId) + { + $wxpayService = new WechatPayService($distributorId, false); + $wxpayServiceWrapper = new PaymentsService($wxpayService); + $wxpayConfig = $wxpayServiceWrapper->getPaymentSetting($companyId); + + $requiredFields = ['app_id', 'merchant_id', 'key', 'cert', 'cert_key']; + + foreach ($requiredFields as $field) { + $value = $wxpayConfig[$field] ?? ''; + if (empty($value) && $value !== '0') { + if ($distributorId > 0) { + throw new ResourceException(trans('DistributionBundle/Services/DistributorService.distributor_wxpay_config_incomplete')); + } else { + throw new ResourceException(trans('DistributionBundle/Services/DistributorService.platform_wxpay_config_incomplete')); + } + } + } + } + + /** + * 校验支付宝配置 + * + * @param int $companyId 公司ID + * @param int $distributorId 店铺ID,0表示平台 + * @throws ResourceException + */ + private function validateAlipayConfig($companyId, $distributorId) + { + $alipayService = new AlipayService($distributorId, false); + $alipayServiceWrapper = new PaymentsService($alipayService); + $alipayConfig = $alipayServiceWrapper->getPaymentSetting($companyId); + + $requiredFields = ['app_id', 'ali_public_key', 'private_key']; + + foreach ($requiredFields as $field) { + $value = $alipayConfig[$field] ?? ''; + if (empty($value) && $value !== '0') { + if ($distributorId > 0) { + throw new ResourceException(trans('DistributionBundle/Services/DistributorService.distributor_alipay_config_incomplete')); + } else { + throw new ResourceException(trans('DistributionBundle/Services/DistributorService.platform_alipay_config_incomplete')); + } + } + } + } } diff --git a/src/DistributionBundle/Services/UploadDistributor.php b/src/DistributionBundle/Services/UploadDistributor.php index 01088a9..97466d5 100644 --- a/src/DistributionBundle/Services/UploadDistributor.php +++ b/src/DistributionBundle/Services/UploadDistributor.php @@ -62,8 +62,8 @@ class UploadDistributor '店铺详细地址门牌号' => ['size' => 255, 'remarks' => '店铺详细地址门牌号', 'is_need' => false], '经营开始时间' => ['size' => 255, 'remarks' => '经营开始时间,以0点开始,半个小时一分隔,excel文本类型', 'is_need' => false], '经营结束时间' => ['size' => 255, 'remarks' => '经营结束时间,以0点开始,半个小时一分隔,结束营业时间需小于开始时间,excel文本类型', 'is_need' => false], - '开启快递配送' => ['size' => 255, 'remarks' => '开启快递配送,1是0否', 'is_need' => true], - '自动同步商品' => ['size' => 255, 'remarks' => '自动同步商品,1是0否', 'is_need' => true], + '开启快递配送' => ['size' => 255, 'remarks' => '开启快递配送,是或否', 'is_need' => true], + '自动同步商品' => ['size' => 255, 'remarks' => '自动同步商品,是或否', 'is_need' => true], '店铺LOGO' => ['size' => 255, 'remarks' => '店铺LOGO', 'is_need' => false], '店铺背景' => ['size' => 255, 'remarks' => '店铺背景', 'is_need' => false], '旺店通ERP店铺号' => ['size' => 255, 'remarks' => '旺店通ERP店铺号', 'is_need' => false], @@ -207,7 +207,19 @@ class UploadDistributor ]; if (!empty($data['hour1']) && !empty($data['hour2'])) { - $insertData['hour'] = $data['hour1'] . '-' . $data['hour2']; + // 验证时间格式,必须是 HH:MM 格式(如 02:00) + $hour1 = trim($data['hour1']); + $hour2 = trim($data['hour2']); + + // 验证格式:必须是 HH:MM,且只能有一个冒号 + if (!preg_match('/^([0-1][0-9]|2[0-3]):([0-5][0-9])$/', $hour1)) { + throw new ResourceException('错误,经营开始时间格式错误'); + } + if (!preg_match('/^([0-1][0-9]|2[0-3]):([0-5][0-9])$/', $hour2)) { + throw new ResourceException('错误,经营结束时间格式错误'); + } + + $insertData['hour'] = $hour1 . '-' . $hour2; } if ($data['is_delivery'] === '是') { @@ -235,7 +247,26 @@ class UploadDistributor $insertData['jst_shop_id'] = $data['jst_shop_id']; } - $mapData = MapService::make($companyId)->getLatAndLng($fir.$sec.$thi, $data['addr2']); + // 拼接完整地址,与getAreaByAddress API保持一致 + // 如果城市和省相同(如直辖市),只保留一个 + if ($fir === $sec) { + $fullAddress = $sec . $thi . ($data['addr2'] ?? ''); + } else { + $fullAddress = $fir . $sec . $thi . ($data['addr2'] ?? ''); + } + + // region参数只传城市名(去除"市"、"省"等后缀),用于限制搜索范围 + // 腾讯地图API要求region只传城市名,如"上海",不能传"上海市"或"上海市上海市徐汇区" + // 如果城市和省相同,使用省名;否则使用城市名 + $regionName = ($fir === $sec) ? $fir : $sec; + $cityName = str_replace(['市', '省', '自治区', '特别行政区'], '', $regionName); + + // 使用完整地址获取经纬度,region参数传入城市名用于限制搜索范围 + $mapData = MapService::make($companyId)->getLatAndLng($cityName, $fullAddress); + app('log')->info('uploadDistributor::region::'.$cityName.'::fullAddress::'.$fullAddress.'::mapData:'.json_encode([ + 'lat' => $mapData->getLat(), + 'lng' => $mapData->getLng() + ])); $insertData["lat"] = $mapData->getLat(); // 经度 $insertData["lng"] = $mapData->getLng(); // 纬度 $distributorData = $distributorRepository->getInfo(['shop_code' => $data['shop_code']]); diff --git a/src/EspierBundle/Commands/InitMultiLangCommand.php b/src/EspierBundle/Commands/InitMultiLangCommand.php index e8f3c5a..1ee0270 100644 --- a/src/EspierBundle/Commands/InitMultiLangCommand.php +++ b/src/EspierBundle/Commands/InitMultiLangCommand.php @@ -58,8 +58,17 @@ class InitMultiLangCommand extends Command $moduleArr = ['item','other']; foreach($moduleArr as $module){ (new \CompanysBundle\MultiLang\MultiLangItem($lang,$module))->createTable(); + + $this->writeLangueConfig($lang); } // (new \CompanysBundle\MultiLang\MultiLangItem('zh-CN','other'))->createTable();dd(11); } + // 写入config/langue.php + private function writeLangueConfig($lang){ + $config = config('langue'); + $config[] = $lang; + file_put_contents(config_path('langue.php'),' '售后类型', 'aftersales_status' => '售后状态', 'create_time' => '创建时间', - 'refund_fee' => '退款金额', + 'refund_fee' => '退款商品金额', + 'refund_point' => '退款抵扣积分', + 'refund_freight_fee' => '退款运费金额(¥)', + 'refund_freight_point' => '退款运费(积分)', + 'refunded_fee' => '实退金额', + 'refunded_point' => '实退积分', 'progress' => '处理进度', 'description' => '申请描述', 'reason' => '申请售后原因', 'refuse_reason' => '拒绝原因', - 'memo' => '售后备注' + 'memo' => '售后备注', + 'salesman_name' => '导购', + 'order_holder' => '订单分类', + 'supplier_name' => '来源供应商', + 'self_delivery_operator_name' => '配送员' ]; public function exportData($filter) @@ -52,19 +67,35 @@ class AftersalesRecordExportService implements ExportFileInterface if (!$count) { return []; } + + // 获取公司产品模式,动态调整title + $companysActivationEgo = new CompanysActivationEgo(); + $companyInfo = $companysActivationEgo->check($filter['company_id']); + $productModel = $companyInfo['product_model'] ?? config('common.product_model', 'platform'); + + // 根据product_model调整title,仅在standard时显示导购字段 + $title = $this->title; + if ($productModel != 'standard') { + unset($title['salesman_name']); + } + $fileName = date('YmdHis').'_售后列表'; - $datalist = $this->getLists($filter, $count); + $datalist = $this->getLists($filter, $count, $productModel); $exportService = new ExportFileService(); // 指定需要作为文本处理的数字字段,避免 Excel 显示为科学计数法 $textFields = ['order_id', 'aftersales_bn', 'item_bn']; - $result = $exportService->exportCsv($fileName, $this->title, $datalist, $textFields); + $result = $exportService->exportCsv($fileName, $title, $datalist, $textFields); return $result; } - private function getLists($filter, $count) + private function getLists($filter, $count, $productModel = null) { + // 根据product_model调整title,仅在standard时显示导购字段 $title = $this->title; + if ($productModel && $productModel != 'standard') { + unset($title['salesman_name']); + } $aftersales_type = [ 'ONLY_REFUND' => '仅退款', @@ -93,10 +124,28 @@ class AftersalesRecordExportService implements ExportFileInterface 9 => '退款处理中', ]; + $orderHolder = [ + 'self' => '自营订单', + 'distributor' => '商家订单', + 'supplier' => '供应商订单', + 'self_supplier' => '自营+供应商订单', + 'distributor_supplier' => '商家+供应商订单' + ]; + if ($count > 0) { $aftersalesService = new AftersalesService(); $tradeService = new TradeService(); + $aftersalesRefundService = new AftersalesRefundService(); + $normalOrderService = new NormalOrderService(); + $supplierService = new SupplierService(); + $salespersonService = new SalespersonService(); + $companysActivationEgo = new CompanysActivationEgo(); + $operatorsRepository = app('registry')->getManager('default')->getRepository(\CompanysBundle\Entities\Operators::class); + // 获取公司产品模式(参照api/company/activate接口的实现) + $companyInfo = $companysActivationEgo->check($filter['company_id']); + $productModel = $companyInfo['product_model'] ?? config('common.product_model', 'platform'); + app('log')->debug('AftersalesRecordExportServic::company_id:'.$filter['company_id'].'companyInfo===>'.json_encode($companyInfo)); $limit = 500; $fileNum = ceil($count / $limit); @@ -107,16 +156,149 @@ class AftersalesRecordExportService implements ExportFileInterface $orderIdList = array_column($data['list'], 'order_id'); $tradeIndex = $tradeService->getTradeIndexByOrderIdList($filter['company_id'], $orderIdList); + // 获取订单信息(order_holder, salesman_id, self_delivery_operator_id) + $orderData = []; + if (!empty($orderIdList)) { + $orderRs = $normalOrderService->normalOrdersRepository->getList( + ['company_id' => $filter['company_id'], 'order_id' => $orderIdList], + 0, + -1, + null, + 'order_id, order_holder, salesman_id, self_delivery_operator_id' + ); + if ($orderRs) { + $orderData = array_column($orderRs, null, 'order_id'); + } + } + + // 获取售后单的supplier_id和self_delivery_operator_id(从aftersales表获取) + $aftersalesBns = array_column($data['list'], 'aftersales_bn'); + $aftersalesSupplierData = []; + $aftersalesOperatorData = []; + if (!empty($aftersalesBns)) { + $conn = app('registry')->getConnection('default'); + $aftersalesQuery = $conn->createQueryBuilder(); + $aftersalesQuery->select('aftersales_bn, supplier_id, self_delivery_operator_id') + ->from('aftersales', 'a') + ->where($aftersalesQuery->expr()->in('a.aftersales_bn', ':bns')); + $aftersalesQuery->setParameter('bns', $aftersalesBns, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY); + $aftersalesRs = $aftersalesQuery->execute()->fetchAll(); + $aftersalesSupplierData = array_column($aftersalesRs, 'supplier_id', 'aftersales_bn'); + $aftersalesOperatorData = array_column($aftersalesRs, 'self_delivery_operator_id', 'aftersales_bn'); + } + + // 获取供应商信息 + $supplierData = []; + $supplierIds = array_filter(array_unique(array_values($aftersalesSupplierData))); + if (!empty($supplierIds)) { + $rs = $supplierService->repository->getLists(['operator_id' => $supplierIds], 'operator_id, supplier_name'); + $supplierData = array_column($rs, 'supplier_name', 'operator_id'); + } + + // 获取导购信息(仅当product_model为standard时) + $salespersonList = []; + if ($productModel == 'standard') { + $salespersonIds = array_filter(array_unique(array_column($orderRs ?? [], 'salesman_id'))); + if (!empty($salespersonIds)) { + $filterSalesperson['company_id'] = $filter['company_id']; + $filterSalesperson['salesperson_id'] = $salespersonIds; + $filterSalesperson['salesperson_type'] = 'shopping_guide'; + $salespersonListTmp = $salespersonService->getLists($filterSalesperson, 'salesperson_id,name,work_userid', 1, -1); + $salespersonList = array_column($salespersonListTmp, null, 'salesperson_id'); + } + } + + // 获取配送员信息(从售后单的self_delivery_operator_id获取) + $selfDeliveryOperator = []; + $selfDeliveryOperatorIds = array_filter(array_unique(array_values($aftersalesOperatorData))); + if (!empty($selfDeliveryOperatorIds)) { + $operatorListResult = $operatorsRepository->lists(['operator_id' => $selfDeliveryOperatorIds]); + $operatorList = $operatorListResult['list'] ?? []; + $selfDeliveryOperator = array_column($operatorList, 'username', 'operator_id'); + } + + // 获取售后退款数据 + $aftersalesBnData = []; + if (!empty($aftersalesBns)) { + $aftersalesBnTmp = $aftersalesRefundService->getRefundsList(['company_id' => $filter['company_id'], 'aftersales_bn' => $aftersalesBns], 0, -1); + $aftersalesBnData = array_column($aftersalesBnTmp['list'], null, 'aftersales_bn'); + } + foreach ($data['list'] as $key => $value) { $value['trade_no'] = $tradeIndex[$value['order_id']] ?? '-'; + // 获取退款数据 + $refundData = $aftersalesBnData[$value['aftersales_bn']] ?? []; + + // 获取订单信息 + $orderInfo = $orderData[$value['order_id']] ?? []; + + // 获取供应商ID + $supplierId = $aftersalesSupplierData[$value['aftersales_bn']] ?? 0; + + // 获取售后单的配送员ID + $aftersalesOperatorId = $aftersalesOperatorData[$value['aftersales_bn']] ?? 0; + foreach ($title as $k => $v) { if ($k == 'create_time') { $recordData[$key][$k] = date('Y-m-d H:i:s', $value[$k]); } elseif (in_array($k, ['order_id', 'aftersales_bn']) && isset($value[$k])) { // 直接赋值,不再添加引号,由 ExportFileService 统一处理 $recordData[$key][$k] = $value[$k]; + } elseif ($k == 'salesman_name') { + // 导购:仅在product_model为standard时显示 + if ($productModel == 'standard') { + $salesmanId = $orderInfo['salesman_id'] ?? 0; + $recordData[$key][$k] = $salespersonList[$salesmanId]['work_userid'] ?? ''; + } else { + $recordData[$key][$k] = ''; + } + } elseif ($k == 'order_holder') { + // 订单分类:转换为中文 + $orderHolderValue = $orderInfo['order_holder'] ?? ''; + $recordData[$key][$k] = $orderHolder[$orderHolderValue] ?? ($orderHolderValue ?: ''); + } elseif ($k == 'supplier_name') { + // 来源供应商 + $recordData[$key][$k] = $supplierData[$supplierId] ?? ''; + } elseif ($k == 'self_delivery_operator_name') { + // 配送员(从售后单的self_delivery_operator_id获取) + $recordData[$key][$k] = $selfDeliveryOperator[$aftersalesOperatorId] ?? ''; } elseif ($k == 'refund_fee') { $recordData[$key][$k] = $value[$k] / 100; + } elseif ($k == 'refund_point') { + // 退款抵扣积分:有退款记录但值为0时显示0,无退款记录时显示-- + if (!empty($refundData) && array_key_exists('refund_point', $refundData)) { + $recordData[$key][$k] = $refundData['refund_point']; + } else { + $recordData[$key][$k] = '--'; + } + } elseif ($k == 'refund_freight_fee') { + // 退款运费金额(¥),根据freight_type判断,如果是cash需要转换为元,没有的则显示0 + if (!empty($refundData) && isset($refundData['freight_type']) && $refundData['freight_type'] == 'cash' && isset($refundData['freight'])) { + $recordData[$key][$k] = $refundData['freight'] / 100; + } else { + $recordData[$key][$k] = 0; + } + } elseif ($k == 'refund_freight_point') { + // 退款运费(积分),根据freight_type判断,如果是point不用转换,没有的则显示0 + if (!empty($refundData) && isset($refundData['freight_type']) && $refundData['freight_type'] == 'point' && isset($refundData['freight'])) { + $recordData[$key][$k] = $refundData['freight']; + } else { + $recordData[$key][$k] = 0; + } + } elseif ($k == 'refunded_fee') { + // 实退金额,需转换为元:有退款记录但值为0时显示0,无退款记录时显示-- + if (!empty($refundData) && array_key_exists('refunded_fee', $refundData)) { + $recordData[$key][$k] = $refundData['refunded_fee'] / 100; + } else { + $recordData[$key][$k] = '--'; + } + } elseif ($k == 'refunded_point') { + // 实退积分:有退款记录但值为0时显示0,无退款记录时显示-- + if (!empty($refundData) && array_key_exists('refunded_point', $refundData)) { + $recordData[$key][$k] = $refundData['refunded_point']; + } else { + $recordData[$key][$k] = '--'; + } } elseif ($k == "aftersales_type") { $recordData[$key][$k] = $aftersales_type[$value[$k]] ?? '--'; } elseif ($k == "aftersales_status") { diff --git a/src/EspierBundle/Services/Export/RefundRecordExportService.php b/src/EspierBundle/Services/Export/RefundRecordExportService.php index bd58e2e..006c455 100644 --- a/src/EspierBundle/Services/Export/RefundRecordExportService.php +++ b/src/EspierBundle/Services/Export/RefundRecordExportService.php @@ -35,9 +35,11 @@ class RefundRecordExportService implements ExportFileInterface 'refund_type' => '退款类型', 'refund_channel' => '退款方式', 'refund_status' => '退款状态', - 'refund_fee' => '应退金额', - 'refunded_fee' => '实退金额', - 'refund_point' => '退款积分', + 'refund_fee' => '应退商品金额', + 'refunded_fee' => '实退商品金额', + 'refund_point' => '退款商品积分', + 'refund_freight_fee' => '退款运费金额(¥)', + 'refund_freight_point' => '退款运费(积分)', 'create_time' => '创建时间', 'refund_success_time' => '退款成功时间', ]; @@ -117,6 +119,20 @@ class RefundRecordExportService implements ExportFileInterface $recordData[$key][$k] = $value[$k]; } elseif (in_array($k, ['refund_fee', 'refunded_fee'])) { $recordData[$key][$k] = $value[$k] / 100; + } elseif ($k == 'refund_freight_fee') { + // 退款运费金额(¥),根据freight_type判断,如果是cash需要转换为元,没有的则显示0 + if (isset($value['freight_type']) && $value['freight_type'] == 'cash' && isset($value['freight'])) { + $recordData[$key][$k] = $value['freight'] / 100; + } else { + $recordData[$key][$k] = 0; + } + } elseif ($k == 'refund_freight_point') { + // 退款运费(积分),根据freight_type判断,如果是point不用转换,没有的则显示0 + if (isset($value['freight_type']) && $value['freight_type'] == 'point' && isset($value['freight'])) { + $recordData[$key][$k] = $value['freight']; + } else { + $recordData[$key][$k] = 0; + } } elseif ($k == "refund_type") { $recordData[$key][$k] = $refund_type[$value[$k]] ?? '--'; } elseif ($k == "refund_channel") { diff --git a/src/EspierBundle/Services/Export/Template/TemplateSheetExport.php b/src/EspierBundle/Services/Export/Template/TemplateSheetExport.php index dc894fd..d22606a 100644 --- a/src/EspierBundle/Services/Export/Template/TemplateSheetExport.php +++ b/src/EspierBundle/Services/Export/Template/TemplateSheetExport.php @@ -22,6 +22,7 @@ use Maatwebsite\Excel\Concerns\WithHeadings; use Maatwebsite\Excel\Concerns\WithTitle; use Maatwebsite\Excel\Concerns\WithStyles; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use PhpOffice\PhpSpreadsheet\Style\NumberFormat; // sheet1模板 class TemplateSheetExport implements FromArray, WithTitle, WithHeadings, WithStyles @@ -32,6 +33,7 @@ class TemplateSheetExport implements FromArray, WithTitle, WithHeadings, WithSty $params = [ 'sheetname' => 'sheet名称', 'list' => [], // 单元格列表,包括头部 + 'textColumns' => [], // 需要设置为文本格式的列索引数组(从1开始)或列名数组 ]; */ public function __construct($params) @@ -68,7 +70,49 @@ class TemplateSheetExport implements FromArray, WithTitle, WithHeadings, WithSty return $this->sheetData['sheetname']; } + /** + * 设置单元格样式 + * @param Worksheet $sheet + */ public function styles(Worksheet $sheet) { + // 如果指定了需要设置为文本格式的列 + if (isset($this->sheetData['textColumns']) && !empty($this->sheetData['textColumns'])) { + $textColumns = $this->sheetData['textColumns']; + + // 获取表头行(第一行) + $headerRow = isset($this->sheetData['list'][0]) ? $this->sheetData['list'][0] : []; + + foreach ($textColumns as $column) { + $colIndex = null; + + // 如果传入的是列名,查找对应的列索引 + if (is_string($column)) { + $foundIndex = array_search($column, $headerRow, true); + if ($foundIndex !== false) { + $colIndex = $foundIndex + 1; // 转换为1-based索引 + } + } elseif (is_numeric($column)) { + // 如果传入的是数字索引(1-based) + $colIndex = (int)$column; + } + + if ($colIndex !== null && $colIndex > 0) { + // 将数字索引转换为列字母(A, B, C, ...) + $colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($colIndex); + + // 设置整列为文本格式(从第2行开始,第1行是表头) + $highestRow = $sheet->getHighestRow(); + if ($highestRow < 2) { + $highestRow = 1000; // 如果只有表头,设置一个默认行数 + } + + // 设置整列的格式为文本 + $sheet->getStyle($colLetter . '2:' . $colLetter . $highestRow) + ->getNumberFormat() + ->setFormatCode(NumberFormat::FORMAT_TEXT); + } + } + } } } diff --git a/src/EspierBundle/Services/Export/TradeExportService.php b/src/EspierBundle/Services/Export/TradeExportService.php index 199be19..1e14634 100644 --- a/src/EspierBundle/Services/Export/TradeExportService.php +++ b/src/EspierBundle/Services/Export/TradeExportService.php @@ -99,7 +99,14 @@ class TradeExportService implements ExportFileInterface 'deposit' => '预存款', 'wxpay' => '微信', 'pos' => 'POS刷卡', - 'localPay' => '零元订单' + 'localPay' => '零元订单', + 'offline_pay' => '线下转账', + 'point' => '积分支付', + 'wxpaypos' => '微信扫码支付', + 'wxpayh5' => '微信H5支付', + 'wxpaypc' => '微信PC支付', + 'alipay' => '支付宝支付', + 'alipayh5' => '支付宝H5支付', ]; $tradeService = new TradeService(); $memberService = new MemberService(); @@ -170,7 +177,12 @@ class TradeExportService implements ExportFileInterface } elseif ($k == "tradeState" && isset($value[$k])) { $orderList[$key][$k] = $tradeState[$value[$k]] ?? '--'; } elseif ($k == "payType" && isset($value[$k])) { - $orderList[$key][$k] = $payType[$value[$k]] ?? '--'; + // 特殊处理:当 payType='localPay' 且 payChannel='offline_pay' 时,显示为"线下转账" + if ($value[$k] == 'localPay' && isset($value['payChannel']) && $value['payChannel'] == 'offline_pay') { + $orderList[$key][$k] = '线下转账'; + } else { + $orderList[$key][$k] = $payType[$value[$k]] ?? '--'; + } } elseif ($k == "store_name") { $orderList[$key][$k] = $storeData[$value['distributorId']]['name'] ?? '--'; } elseif ($k == "shop_name") { diff --git a/src/EspierBundle/Services/UploadFileService.php b/src/EspierBundle/Services/UploadFileService.php index 680ab18..445c1a7 100644 --- a/src/EspierBundle/Services/UploadFileService.php +++ b/src/EspierBundle/Services/UploadFileService.php @@ -261,10 +261,20 @@ class UploadFileService $demoDataList = $this->uploadFile->getDemoData(); } + // 确定需要设置为文本格式的列 + $textColumns = []; + if (method_exists($this->uploadFile, 'getTextColumns')) { + $textColumns = $this->uploadFile->getTextColumns(); + } elseif ($fileType === 'distributor_info') { + // 对于分销商信息模板,设置"经营开始时间"和"经营结束时间"为文本格式 + $textColumns = ['经营开始时间', '经营结束时间']; + } + $data = [ [ 'sheetname' => $fileName, 'list' => array_merge($dataList, $demoDataList), + 'textColumns' => $textColumns, ] ]; if ($title['headerInfo']) { diff --git a/src/GoodsBundle/Services/ItemsAttributesService.php b/src/GoodsBundle/Services/ItemsAttributesService.php index 07b6858..ca4491e 100644 --- a/src/GoodsBundle/Services/ItemsAttributesService.php +++ b/src/GoodsBundle/Services/ItemsAttributesService.php @@ -23,6 +23,8 @@ use GoodsBundle\Entities\ItemsAttributeValues; use GoodsBundle\Entities\ItemRelAttributes; use Dingo\Api\Exception\ResourceException; use GoodsBundle\Repositories\ItemsAttributeValuesRepository; +use PointsmallBundle\Entities\PointsmallItemRelAttributes; +use PointsmallBundle\Entities\PointsmallItems; class ItemsAttributesService { @@ -147,19 +149,37 @@ class ItemsAttributesService $relItemsData = $itemRelAttributesRepository->lists($filter, 1, -1); if ($relItemsData['total_count'] > 0) { $itemIdList = array_column($relItemsData['list'], 'item_id'); - if (empty($itemIdList)) { - return true; - } - $itemsRepository = app('registry')->getManager('default')->getRepository(Items::class); - $itemFilter = [ - 'company_id' => $companyId, - 'item_id' => $itemIdList - ]; - $itemList = $itemsRepository->getItemsLists($itemFilter); - if (!empty($itemList)) { - throw new ResourceException(trans('GoodsBundle/Controllers/Items.has_associated_items')); + if (!empty($itemIdList)) { + $itemsRepository = app('registry')->getManager('default')->getRepository(Items::class); + $itemFilter = [ + 'company_id' => $companyId, + 'item_id' => $itemIdList + ]; + $itemList = $itemsRepository->getItemsLists($itemFilter); + if (!empty($itemList)) { + throw new ResourceException(trans('GoodsBundle/Controllers/Items.has_associated_items')); + } } } + + // 检查积分商城商品 + $pointsmallItemRelAttributesRepository = app('registry')->getManager('default')->getRepository(PointsmallItemRelAttributes::class); + $pointsmallRelData = $pointsmallItemRelAttributesRepository->lists($filter, 1, -1); + if ($pointsmallRelData['total_count'] > 0) { + $pointsmallItemIds = array_column($pointsmallRelData['list'], 'item_id'); + if (!empty($pointsmallItemIds)) { + $pointsmallItemsRepository = app('registry')->getManager('default')->getRepository(PointsmallItems::class); + $pointsmallItemFilter = [ + 'company_id' => $companyId, + 'item_id' => $pointsmallItemIds + ]; + $pointsmallItemList = $pointsmallItemsRepository->getItemsLists($pointsmallItemFilter); + if (!empty($pointsmallItemList)) { + throw new ResourceException(trans('GoodsBundle/Controllers/Items.has_associated_pointsmall_items')); + } + } + } + return true; } diff --git a/src/KaquanBundle/Http/FrontApi/V1/Action/DiscountCard.php b/src/KaquanBundle/Http/FrontApi/V1/Action/DiscountCard.php index 80ea949..bc9c874 100644 --- a/src/KaquanBundle/Http/FrontApi/V1/Action/DiscountCard.php +++ b/src/KaquanBundle/Http/FrontApi/V1/Action/DiscountCard.php @@ -116,7 +116,7 @@ class DiscountCard extends BaseController if ($distributorId == 'all') { unset($filter['distributor_id']); } - $filter['receive'] = 'true'; + $filter['receive'] = '1'; $filter['company_id'] = $authInfo['company_id']; $discountCardService = new KaquanService(new DiscountCardService()); diff --git a/src/KaquanBundle/Repositories/DiscountCardsRepository.php b/src/KaquanBundle/Repositories/DiscountCardsRepository.php index c94ede7..9a09cec 100644 --- a/src/KaquanBundle/Repositories/DiscountCardsRepository.php +++ b/src/KaquanBundle/Repositories/DiscountCardsRepository.php @@ -723,11 +723,8 @@ class DiscountCardsRepository extends EntityRepository $entity->setSelfConsumeCode($data["self_consume_code"]); } //当前字段非必填 - if (isset($data['receive']) && $data['receive']) { + if (isset($data['receive'])) { $entity->setReceive($data['receive']); - } else { - // 'true' - $entity->setReceive(true); } if (isset($data["created"]) && $data["created"]) { $entity->setCreated($data["created"]); diff --git a/src/KaquanBundle/Services/DiscountCardService.php b/src/KaquanBundle/Services/DiscountCardService.php index fef62ff..eb815b6 100644 --- a/src/KaquanBundle/Services/DiscountCardService.php +++ b/src/KaquanBundle/Services/DiscountCardService.php @@ -531,7 +531,8 @@ class DiscountCardService implements KaquanInterface $detail['use_scenes'] = "QUICK"; } - $detail['receive'] = ($detail['receive'] == 'true') ? true : false; + // receive 字段在数据库中存储为整数 0 或 1,转换为布尔值返回 + $detail['receive'] = ($detail['receive'] == '1' || $detail['receive'] == 1) ? true : false; $detail['tag_ids'] = $detail['rel_tag_ids'] = array_filter(explode(',', $detail['tag_ids'])); //获取商品标签 @@ -1442,6 +1443,11 @@ class DiscountCardService implements KaquanInterface $dataInfo['tag_ids'] = ''; $dataInfo['create_queue'] = true; } + + // 处理 receive 字段,统一转换为整数 0 或 1 + if (isset($dataInfo['receive'])) { + $dataInfo['receive'] = $dataInfo['receive'] == true ? 1 : 0; + } } //这里不再返回 item_id diff --git a/src/KaquanBundle/Services/DiscountNewGiftCardService.php b/src/KaquanBundle/Services/DiscountNewGiftCardService.php index e86780f..9168304 100644 --- a/src/KaquanBundle/Services/DiscountNewGiftCardService.php +++ b/src/KaquanBundle/Services/DiscountNewGiftCardService.php @@ -283,11 +283,11 @@ class DiscountNewGiftCardService implements KaquanInterface throw new ResourceException(trans('KaquanBundle.lock_time_cannot_exceed_usage_time')); } - // wtf + // 处理 receive 字段,统一转换为整数 0 或 1 if (isset($params['receive'])) { - $params['receive'] = ($params['receive'] == 'true') ? 'true' : 'false'; + $params['receive'] = $params['receive'] == true ? 1 : 0; } elseif ($is_create) { - $params['receive'] = 'false'; + $params['receive'] = 0; } // 照着以前的逻辑转义这些参数 diff --git a/src/KaquanBundle/Services/UserDiscountService.php b/src/KaquanBundle/Services/UserDiscountService.php index cd70e62..3ebe1ec 100644 --- a/src/KaquanBundle/Services/UserDiscountService.php +++ b/src/KaquanBundle/Services/UserDiscountService.php @@ -135,7 +135,7 @@ class UserDiscountService implements UserDiscountInterface } } - if ($from == 'template' && $item['receive'] != 'true') { + if ($from == 'template' && $item['receive'] != '1' && $item['receive'] != 1) { $checkResult[] = [ 'card_info' => $item, 'message' => trans('KaquanBundle.coupon_not_frontend_receivable'), diff --git a/src/OrdersBundle/Http/Api/V1/Action/Trade.php b/src/OrdersBundle/Http/Api/V1/Action/Trade.php index df59feb..208ff19 100644 --- a/src/OrdersBundle/Http/Api/V1/Action/Trade.php +++ b/src/OrdersBundle/Http/Api/V1/Action/Trade.php @@ -157,7 +157,6 @@ class Trade extends Controller $page = $request->input('page', 1); $orderBy = ['time_start' => 'DESC']; - $filter['filter_order_type'] = $request->input('order_type'); $data = $tradeService->getTradeList($filter, $orderBy, $pageSize, $page); if ($data['list']) { diff --git a/src/OrdersBundle/Services/OrderInvoiceService.php b/src/OrdersBundle/Services/OrderInvoiceService.php index 24e9a7b..8f518ad 100644 --- a/src/OrdersBundle/Services/OrderInvoiceService.php +++ b/src/OrdersBundle/Services/OrderInvoiceService.php @@ -1581,17 +1581,12 @@ class OrderInvoiceService //查询公司id的申请开票节点 $settingService = new SettingService(); foreach ($companyIds as $companyId) { - $applyNodeArr[$companyId] = $settingService->getInvoiceSetting($companyId)['apply_node']; + $setting = $settingService->getInvoiceSetting($companyId); + if ($setting && isset($setting['apply_node'])) { + $applyNodeArr[$companyId] = $setting['apply_node']; + } } - // 获取设置 - **apply_node**:申请开票节点(1=确认收货,2=过售后期) - // $applyNode = app('config')->get('invoice.apply_node'); - // $settingService = new SettingService(); - // $companyId = env('SYSTEM_MAIN_COMPANYS_ID',1); - // $applyNode = $settingService->getInvoiceSetting($companyId)['apply_node']; - - // app('log')->info('[OrderInvoiceService][invoiceStartSchedule](1=确认收货,2=过售后期) 申请开票节点: ' . $applyNode); - foreach ($applyNodeArr as $companyId => $applyNode) { if ($applyNode == 1) { $filter['end_time|lt'] = time(); @@ -1630,7 +1625,7 @@ class OrderInvoiceService ]; // 推送到 invoice 队列 - dispatch(new \OrdersBundle\Jobs\InvoiceCreateJob($jobData))->onQueue('invoice'); + dispatch(new \OrdersBundle\Jobs\InvoiceCreateJob($jobData))->onQueue('slow'); app('log')->info('[OrderInvoiceService][invoiceStartSchedule] 发票申请 ID: ' . $invoice['id'] . ' 已推送到队列'); @@ -1701,7 +1696,7 @@ class OrderInvoiceService ]; // 推送到 invoice 队列 - dispatch(new \OrdersBundle\Jobs\InvoiceRedQueryJob($jobData))->onQueue('invoice'); + dispatch(new \OrdersBundle\Jobs\InvoiceRedQueryJob($jobData))->onQueue('slow'); app('log')->info('[OrderInvoiceService][invoiceRedQuerySchedule] 红冲发票 ID: ' . $invoice['id'] . ' 已推送到队列'); @@ -2089,8 +2084,8 @@ class OrderInvoiceService 'order_id' => $invoice['order_id'] ]; app('log')->info('[OrderInvoiceService][queryInvoiceSchedule] 发票查询任务:jobData:', $jobData); - // 推送到 invoice_query 队列 - dispatch(new \OrdersBundle\Jobs\InvoiceQueryJob($jobData))->onQueue('invoice_query'); + + dispatch(new \OrdersBundle\Jobs\InvoiceQueryJob($jobData))->onQueue('slow'); app('log')->info('[OrderInvoiceService][queryInvoiceSchedule] 发票查询任务 ID: ' . $invoice['id'] . ' 已推送到队列'); diff --git a/src/OrdersBundle/Services/TradeService.php b/src/OrdersBundle/Services/TradeService.php index 58783a1..5b389a6 100644 --- a/src/OrdersBundle/Services/TradeService.php +++ b/src/OrdersBundle/Services/TradeService.php @@ -321,15 +321,19 @@ class TradeService implements InterfacesTrade */ public function getTradeList($filter, $orderBy = ['time_start' => 'DESC'], $pageSize = 20, $page = 1) { - $filterOrderType = $filter['filter_order_type'] ?? false; - unset($filter['filter_order_type']); $filter = $this->checkMobile($filter); $tradeList = $this->tradeRepository->getTradeList($filter, $orderBy, $pageSize, $page); - if ($filterOrderType) { + if ($tradeList['total_count'] > 0) { //提取所有订单号 $orderIds = array_column($tradeList['list'], 'orderId'); - $orderService = $this->getOrderService($filterOrderType); - $orderList = $orderService->lists(['order_id' => $orderIds], null, count($orderIds), 1, false, 'order_id,order_sn'); + $orderService = $this->getOrderService('normal'); + $companyId = $filter['company_id']; + unset($filter); + $filter['company_id'] = $companyId; + $filter['order_id'] = $orderIds; + $orderList = $orderService->getOrderList($filter, 1, count($orderIds), [], false); + $orderListData = array_column($orderList['list'], null, 'order_id'); + $selfDeliveryOperatorIds = array_column($orderList['list'], 'self_delivery_operator_id', 'order_id'); $selfDeliveryOperator = []; if ($selfDeliveryOperatorIds) { @@ -339,10 +343,15 @@ class TradeService implements InterfacesTrade } } foreach ($tradeList['list'] as &$value) { - if (isset($selfDeliveryOperatorIds[$value['orderId']]) && $selfDeliveryOperatorIds[$value['orderId']] > 0) { - $value['self_delivery_operator_id'] = $selfDeliveryOperatorIds[$value['orderId']]; - $value['self_delivery_operator_mobile'] = $selfDeliveryOperator[$value['self_delivery_operator_id']]['mobile']; - $value['self_delivery_operator_name'] = $selfDeliveryOperator[$value['self_delivery_operator_id']]['username']; + if (isset($orderListData[$value['orderId']])) { + $value['receipt_type'] = $orderListData[$value['orderId']]['receipt_type']; + $value['order_holder'] = $orderListData[$value['orderId']]['order_holder']; + $value['self_delivery_fee'] = $orderListData[$value['orderId']]['self_delivery_fee'] ?? 0; + if (isset($selfDeliveryOperatorIds[$value['orderId']]) && $selfDeliveryOperatorIds[$value['orderId']] > 0) { + $value['self_delivery_operator_id'] = $selfDeliveryOperatorIds[$value['orderId']] ?? 0; + $value['self_delivery_operator_mobile'] = $selfDeliveryOperator[$value['self_delivery_operator_id']]['mobile'] ?? ''; + $value['self_delivery_operator_name'] = $selfDeliveryOperator[$value['self_delivery_operator_id']]['username'] ?? ''; + } } } return $tradeList; diff --git a/src/PaymentBundle/Http/Api/V1/Action/Payment.php b/src/PaymentBundle/Http/Api/V1/Action/Payment.php index d2afcfb..f472781 100644 --- a/src/PaymentBundle/Http/Api/V1/Action/Payment.php +++ b/src/PaymentBundle/Http/Api/V1/Action/Payment.php @@ -273,6 +273,49 @@ class Payment extends Controller return $this->response->array($data); } + /** + * @SWG\Get( + * path="/trade/payment/open-status", + * summary="获取支付配置开关状态", + * tags={"订单"}, + * description="获取支付配置开关状态整合信息,统一返回is_open为bool类型", + * operationId="getPaymentOpenStatus", + * @SWG\Parameter( name="Authorization", in="header", description="JWT验证token", required=true, type="string"), + * @SWG\Response( + * response=200, + * description="成功返回结构", + * @SWG\Schema( + * @SWG\Property( + * property="data", + * type="object", + * @SWG\Property(property="wxpay", type="object", + * @SWG\Property(property="is_open", type="boolean", example=true), + * ), + * @SWG\Property(property="alipay", type="object", + * @SWG\Property(property="is_open", type="boolean", example=false), + * ), + * @SWG\Property(property="chinaumspay", type="object", + * @SWG\Property(property="is_open", type="boolean", example=true), + * ), + * ), + * ), + * ), + * @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/PaymentErrorRespones") ) ) + * ) + */ + public function getPaymentOpenStatus(Request $request) + { + $companyId = app('auth')->user()->get('company_id'); + $operatorType = app('auth')->user()->get('operator_type'); + $operatorId = app('auth')->user()->get('operator_id'); + + // 调用Service获取支付开关状态 + $paymentsService = new PaymentsService(); + $result = $paymentsService->getPaymentOpenStatusList($companyId, $operatorType, $operatorId); + + return $this->response->array($result); + } + /** * @SWG\Get( * path="/wxapp/trade/payment/list", diff --git a/src/PaymentBundle/Services/Payments/AlipayService.php b/src/PaymentBundle/Services/Payments/AlipayService.php index b713a2e..b4f59db 100644 --- a/src/PaymentBundle/Services/Payments/AlipayService.php +++ b/src/PaymentBundle/Services/Payments/AlipayService.php @@ -20,11 +20,13 @@ namespace PaymentBundle\Services\Payments; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use PaymentBundle\Interfaces\Payment; +use PaymentBundle\Traits\PaymentSubjectTrait; use OrdersBundle\Events\OrderProcessLogEvent; class AlipayService implements Payment { + use PaymentSubjectTrait; private $distributorId = 0; // 店铺ID private $getDefault = true; //是否取平台默认配置 @@ -36,10 +38,51 @@ class AlipayService implements Payment } /** - * 设置微信支付配置 + * 校验私钥(只做验证,不做格式转换) + * @param string $privateKey 私钥字符串 + * @throws BadRequestHttpException 如果私钥内容无效 + */ + private function validatePrivateKey($privateKey) + { + if (empty($privateKey)) { + return; + } + + $privateKey = trim($privateKey); + + // 如果是 PEM 格式,提取 Base64 内容用于验证 + if (strpos($privateKey, '-----BEGIN') !== false) { + $cleanKey = preg_replace('/-----BEGIN.*?-----/', '', $privateKey); + $cleanKey = preg_replace('/-----END.*?-----/', '', $cleanKey); + $cleanKey = preg_replace('/\s+/', '', $cleanKey); + } else { + // Base64 格式,清理空格和换行 + $cleanKey = preg_replace('/\s+/', '', $privateKey); + } + + // 按 support.php 的处理方式,拼接首尾字符后验证 + $pemKey = "-----BEGIN RSA PRIVATE KEY-----\n" . + wordwrap($cleanKey, 64, "\n", true) . + "\n-----END RSA PRIVATE KEY-----"; + + // 验证私钥是否可以正常解析 + $keyResource = @openssl_pkey_get_private($pemKey); + if ($keyResource === false) { + throw new BadRequestHttpException('私钥内容无效'); + } + @openssl_free_key($keyResource); + } + + /** + * 设置支付宝支付配置 */ public function setPaymentSetting($companyId, $data) { + // 校验私钥(只做验证,不做格式转换) + if (isset($data['private_key']) && !empty($data['private_key'])) { + $this->validatePrivateKey($data['private_key']); + } + return app('redis')->set($this->genReidsId($companyId), json_encode($data)); } @@ -48,13 +91,21 @@ class AlipayService implements Payment */ public function getPaymentSetting($companyId) { - $data = app('redis')->get($this->genReidsId($companyId)); - - //不存在店铺配置取平台的配置 - if (!$data && $this->getDefault && $this->distributorId > 0) { - $this->distributorId = 0; - $data = app('redis')->get($this->genReidsId($companyId)); + // 根据店铺收款主体类型决定实际使用的distributorId + if ($this->getDefault && $this->distributorId > 0) { + $actualDistributorId = $this->getActualDistributorId($this->distributorId, $companyId); + if ($actualDistributorId != $this->distributorId) { + $this->distributorId = $actualDistributorId; + } } + + $data = app('redis')->get($this->genReidsId($companyId)); + // 增加了支付主体的字段,平台or店铺,无论配置是否为空,如果是店铺,则取店铺配置,如果是平台,则取平台配置 + //不存在店铺配置取平台的配置 + // if (!$data && $this->getDefault && $this->distributorId > 0) { + // $this->distributorId = 0; + // $data = app('redis')->get($this->genReidsId($companyId)); + // } $data = json_decode($data, true); if ($data) { diff --git a/src/PaymentBundle/Services/Payments/ChinaumsPayService.php b/src/PaymentBundle/Services/Payments/ChinaumsPayService.php index 3e1a949..331e9e8 100644 --- a/src/PaymentBundle/Services/Payments/ChinaumsPayService.php +++ b/src/PaymentBundle/Services/Payments/ChinaumsPayService.php @@ -19,6 +19,7 @@ namespace PaymentBundle\Services\Payments; use OrdersBundle\Interfaces\Trade; use PaymentBundle\Interfaces\Payment; +use PaymentBundle\Traits\PaymentSubjectTrait; use WechatBundle\Services\OpenPlatform; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use OrdersBundle\Services\TradeService; @@ -35,6 +36,7 @@ use AftersalesBundle\Services\AftersalesRefundService; class ChinaumsPayService implements Payment { use GetOrderServiceTrait; + use PaymentSubjectTrait; private $subKey = ''; // 子商户配置key @@ -82,6 +84,13 @@ class ChinaumsPayService implements Payment if ($subKey) { $this->subKey = $subKey; } + + // 根据店铺收款主体类型决定实际使用的subKey + $actualSubKey = $this->getActualSubKey($this->subKey, $companyId); + if ($actualSubKey != $this->subKey) { + $this->subKey = $actualSubKey; + } + $data = app('redis')->get($this->genReidsId($companyId)); if ($data) { $data = json_decode($data, true); @@ -120,7 +129,7 @@ class ChinaumsPayService implements Payment public function doPay($authorizerAppId, $wxaAppId, array $data) { // 检查店铺支付数据 - $paymentSetting = $this->getPaymentSetting($companyId); + $paymentSetting = $this->getPaymentSetting($data['company_id']); $data['mch_id'] = $paymentSetting['mid']; //-----------------银联支付------------------------------ diff --git a/src/PaymentBundle/Services/Payments/WechatPayService.php b/src/PaymentBundle/Services/Payments/WechatPayService.php index 099d66b..79cd1a9 100644 --- a/src/PaymentBundle/Services/Payments/WechatPayService.php +++ b/src/PaymentBundle/Services/Payments/WechatPayService.php @@ -19,6 +19,7 @@ namespace PaymentBundle\Services\Payments; use OrdersBundle\Interfaces\Trade; use PaymentBundle\Interfaces\Payment; +use PaymentBundle\Traits\PaymentSubjectTrait; use WechatBundle\Services\OpenPlatform; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use OrdersBundle\Services\TradeService; @@ -32,6 +33,7 @@ use PopularizeBundle\Services\CashWithdrawalService as PopularizeCashWithdrawalS class WechatPayService implements Payment { + use PaymentSubjectTrait; public $openid = ''; private $distributorId = 0; // 店铺ID private $getDefault = true; //是否取平台默认配置 @@ -103,13 +105,25 @@ class WechatPayService implements Payment */ public function getPaymentSetting($companyId) { - $data = app('redis')->get($this->genReidsId($companyId)); - - //不存在店铺配置取平台的配置 - if (!$data && $this->getDefault && $this->distributorId > 0) { - $this->distributorId = 0; - $data = app('redis')->get($this->genReidsId($companyId)); + app('log')->debug('payment::getPaymentSettingList::getDefault=>' . $this->getDefault.'distributorId=>' . $this->distributorId); + // 根据店铺收款主体类型决定实际使用的distributorId + if ($this->getDefault && $this->distributorId > 0) { + $actualDistributorId = $this->getActualDistributorId($this->distributorId, $companyId); + app('log')->debug('payment::getPaymentSettingList::actualDistributorId=>' . $actualDistributorId); + if ($actualDistributorId != $this->distributorId) { + $this->distributorId = $actualDistributorId; + } } + + + $data = app('redis')->get($this->genReidsId($companyId)); + app('log')->debug('payment::getPaymentSettingList::data=>' . $data); + // 增加了支付主体的字段,平台or店铺,无论配置是否为空,如果是店铺,则取店铺配置,如果是平台,则取平台配置 + //不存在店铺配置取平台的配置 + // if (!$data && $this->getDefault && $this->distributorId > 0) { + // $this->distributorId = 0; + // $data = app('redis')->get($this->genReidsId($companyId)); + // } if ($data) { $data = json_decode($data, true); diff --git a/src/PaymentBundle/Services/PaymentsService.php b/src/PaymentBundle/Services/PaymentsService.php index 8db320b..f2d7881 100644 --- a/src/PaymentBundle/Services/PaymentsService.php +++ b/src/PaymentBundle/Services/PaymentsService.php @@ -701,4 +701,68 @@ class PaymentsService return $result; } + + /** + * 获取支付配置开关状态列表 + * + * @param int $companyId 公司ID + * @param int $distributorId 店铺ID,0表示平台 + * @param string $operatorType 操作员类型 + * @param int $operatorId 操作员ID + * @return array 返回各支付方式的开关状态 + */ + public function getPaymentOpenStatusList($companyId) + { + $result = []; + + // 微信支付配置 + // 使用 getDefault = true,会根据 payment_subject 自动调整到正确的配置 + $wxpayService = new WechatPayService(0, true); + $wxpayServiceWrapper = new PaymentsService($wxpayService); + $wxpayConfig = $wxpayServiceWrapper->getPaymentSetting($companyId); + $result['wxpay'] = [ + 'is_open' => $this->normalizeIsOpen($wxpayConfig['is_open'] ?? false), + ]; + + // 支付宝配置 + // 使用 getDefault = true,会根据 payment_subject 自动调整到正确的配置 + $alipayService = new AlipayService(0, true); + $alipayServiceWrapper = new PaymentsService($alipayService); + $alipayConfig = $alipayServiceWrapper->getPaymentSetting($companyId); + $result['alipay'] = [ + 'is_open' => $this->normalizeIsOpen($alipayConfig['is_open'] ?? false), + ]; + + $chinaumsService = new ChinaumsPayService(); + $chinaumsServiceWrapper = new PaymentsService($chinaumsService); + $chinaumsConfig = $chinaumsServiceWrapper->getPaymentSetting($companyId); + $result['chinaumspay'] = [ + 'is_open' => $this->normalizeIsOpen($chinaumsConfig['is_open'] ?? false), + ]; + + return $result; + } + + /** + * 统一is_open字段格式为bool类型 + * + * @param mixed $value + * @return bool + */ + private function normalizeIsOpen($value) + { + if (is_bool($value)) { + return $value; + } + + if (is_string($value)) { + return in_array(strtolower($value), ['true', '1', 'yes', 'on']); + } + + if (is_numeric($value)) { + return (bool)$value; + } + + return false; + } } diff --git a/src/PaymentBundle/Traits/PaymentSubjectTrait.php b/src/PaymentBundle/Traits/PaymentSubjectTrait.php new file mode 100644 index 0000000..d3f2185 --- /dev/null +++ b/src/PaymentBundle/Traits/PaymentSubjectTrait.php @@ -0,0 +1,93 @@ +getManager('default')->getRepository(\DistributionBundle\Entities\Distributor::class); + $distributorInfo = $distributorRepository->getInfo([ + 'distributor_id' => $distributorId, + 'company_id' => $companyId + ]); + + if (!$distributorInfo) { + // 店铺不存在,使用平台配置 + return 0; + } + + // payment_subject: 0=平台, 1=店铺 + // 如果收款主体为平台,使用平台配置(distributor_id=0) + // 如果收款主体为店铺,使用店铺配置(返回原distributorId) + return ($distributorInfo['payment_subject'] == 1) ? $distributorId : 0; + } + + /** + * 根据店铺收款主体类型获取实际使用的subKey(用于ChinaumsPayService) + * + * @param string $subKey 子商户配置key,格式:distributor_123 或 dealer_456 + * @param int $companyId 公司ID + * @return string 实际使用的subKey,空字符串表示使用平台配置 + */ + protected function getActualSubKey($subKey, $companyId) + { + // 如果subKey为空或者是dealer_开头,直接返回(不处理) + if (empty($subKey) || strpos($subKey, 'dealer_') === 0) { + return $subKey; + } + + // 从subKey中提取distributorId(格式:distributor_123) + if (strpos($subKey, 'distributor_') === 0) { + $distributorId = (int)str_replace('distributor_', '', $subKey); + + if ($distributorId > 0) { + // 使用getActualDistributorId方法获取实际使用的distributorId + $actualDistributorId = $this->getActualDistributorId($distributorId, $companyId); + + // 如果实际使用的是平台配置,返回空字符串 + if ($actualDistributorId == 0) { + return ''; + } + + // 如果实际使用的是店铺配置,返回原subKey + return $subKey; + } + } + + return $subKey; + } +} + diff --git a/src/PromotionsBundle/Http/Api/V1/Action/SeckillActivity.php b/src/PromotionsBundle/Http/Api/V1/Action/SeckillActivity.php index c69f0f9..b2a9dc2 100644 --- a/src/PromotionsBundle/Http/Api/V1/Action/SeckillActivity.php +++ b/src/PromotionsBundle/Http/Api/V1/Action/SeckillActivity.php @@ -386,7 +386,7 @@ class SeckillActivity extends Controller 'activity_end_time' => ['required', trans('PromotionsBundle.activity_end_time_required')], 'activity_release_time' => ['required', trans('PromotionsBundle.activity_release_time_required')], 'company_id' => ['required', trans('PromotionsBundle.company_id_required')], - 'ad_pic' => ['required', trans('PromotionsBundle.activity_cover_required')], + // 'ad_pic' => ['required', trans('PromotionsBundle.activity_cover_required')], 'items.*.item_id' => ['required', trans('PromotionsBundle.product_id_param_missing')], 'items.*.item_title' => ['required', trans('PromotionsBundle.product_title_param_missing')], 'items.*.activity_price' => ['required', trans('PromotionsBundle.product_activity_price_param_missing')], diff --git a/src/PromotionsBundle/Traits/CheckPromotionsRules.php b/src/PromotionsBundle/Traits/CheckPromotionsRules.php index 7553b2b..70a99e3 100644 --- a/src/PromotionsBundle/Traits/CheckPromotionsRules.php +++ b/src/PromotionsBundle/Traits/CheckPromotionsRules.php @@ -121,10 +121,14 @@ trait CheckPromotionsRules $params['shop_ids'] = explode(',', $activityData['distributor_id']); } + // 限时秒杀和限时特惠都需要检查满减、满折、满赠等活动 if ($activityData['seckill_type'] == 'normal') { $this->checkMarketing($params);//满减,满折,加价购,满赠,会员优先购 $this->checkLimit($params);//检查商品限购 $this->checkPackage($params);//检查组合商品促销 + } elseif ($activityData['seckill_type'] == 'limited_time_sale') { + // 限时特惠也需要检查满减、满折、满赠等活动,但不检查商品限购和组合商品促销 + $this->checkMarketing($params);//满减,满折,加价购,满赠,会员优先购 } $this->checkGroup($params);//检查拼团 @@ -166,7 +170,8 @@ trait CheckPromotionsRules // $params['start_time'] = strtotime($params['start_time']); // $params['end_time'] = strtotime($params['end_time']); $params['shop_ids'] = $params['shop_ids'] ?? []; - $params['seckill_type'] = 'normal';//只排除限时秒杀 + // 满减、满折、满赠等活动需要同时检查限时秒杀和限时特惠 + $params['seckill_type'] = ['normal', 'limited_time_sale']; $marketingType = [$params['marketing_type']];//活动都要排除自身 switch ($params['marketing_type']) { @@ -179,13 +184,14 @@ trait CheckPromotionsRules break; case 'member_preference': - $params['seckill_type'] = 'normal';//会员优先购 和 限时秒杀 冲突 + // 会员优先购只和限时秒杀冲突,不和限时特惠冲突 + $params['seckill_type'] = 'normal'; break; } $this->checkMarketing($params, $marketingType);//满减,满折,加价购, $this->checkGroup($params);//检查拼团 - $this->checkSecKill($params);//检查限时秒杀 + $this->checkSecKill($params);//检查限时秒杀和限时特惠 $this->checkBargain($params);//检查微信助力砍价 return true; } diff --git a/src/SuperAdminBundle/Repositories/ShopMenuRepository.php b/src/SuperAdminBundle/Repositories/ShopMenuRepository.php index 0a35f00..b9335a3 100644 --- a/src/SuperAdminBundle/Repositories/ShopMenuRepository.php +++ b/src/SuperAdminBundle/Repositories/ShopMenuRepository.php @@ -32,7 +32,7 @@ class ShopMenuRepository extends EntityRepository public $module = 'shop_menu'; // 多语言对应的模块 public $primaryKey = 'shopmenu_id'; // 主键,对应data_id public $langField = [ - 'alias_name','name' + 'name' ]; // 多语言字段 public function getEntity() @@ -338,6 +338,17 @@ class ShopMenuRepository extends EntityRepository $data['is_show'] = isset($data['is_show']) && $data['is_show'] == 'false' ? 0 : 1; $data['disabled'] = isset($data['disabled']) && $data['disabled'] == 'true' ? 1 : 0; + // 记录 is_show 从 true 变为 false 的日志 + if (isset($data["is_show"])) { + $oldValue = $entity->getIsShow(); + $newValue = $data['is_show']; + + // 只记录从 true 变为 false 的情况 + if ($oldValue === true && $newValue == 0) { + $this->logIsShowChangeToFalse($entity, $data); + } + } + if (isset($data["shopmenu_id"])) { $entity->setShopmenuId($data["shopmenu_id"]); } @@ -390,6 +401,261 @@ class ShopMenuRepository extends EntityRepository return $entity; } + /** + * 记录 is_show 从 true 变为 false 的日志 + * + * @param $entity + * @param $data + */ + private function logIsShowChangeToFalse($entity, $data) + { + try { + $logData = [ + 'timestamp' => date('Y-m-d H:i:s'), + 'action' => $this->getActionType(), + 'shopmenu_id' => $entity->getShopmenuId() ?: ($data['shopmenu_id'] ?? null), + 'company_id' => $entity->getCompanyId() ?: ($data['company_id'] ?? 0), + 'version' => $entity->getVersion() ?: ($data['version'] ?? 1), + 'alias_name' => $entity->getAliasName() ?: ($data['alias_name'] ?? null), + 'name' => $entity->getName() ?: ($data['name'] ?? null), + 'old_value' => true, + 'new_value' => false, + 'source' => $this->getRequestSource(), + 'source_type' => $this->getSourceType(), + 'user_id' => $this->getUserId(), + 'user_name' => $this->getUserName(), + 'user_email' => $this->getUserEmail(), + 'request_data' => $this->getRequestData($data), + 'ip' => $this->getRequestIp(), + 'user_agent' => $this->getUserAgent(), + 'trace_id' => $this->getTraceId(), + 'stack_trace' => $this->getSimpleStackTrace(), + 'context' => $this->getContext(), + ]; + + $logFile = storage_path('logs/shopmenu_is_show_hidden.log'); + $logLine = json_encode($logData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n"; + file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX); + } catch (\Exception $e) { + // 记录日志失败不影响主流程,静默处理 + } + } + + /** + * 获取操作类型 + */ + private function getActionType() + { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 15); + foreach ($trace as $frame) { + if (isset($frame['function'])) { + if ($frame['function'] == 'create') { + return 'create'; + } + if ($frame['function'] == 'updateOneBy' || $frame['function'] == 'updateBy') { + return 'update'; + } + } + } + return 'unknown'; + } + + /** + * 获取请求来源 + */ + private function getRequestSource() + { + try { + if (php_sapi_name() === 'cli') { + return 'cli'; + } + $request = app('request'); + if ($request) { + return $request->method() . ' ' . $request->path(); + } + } catch (\Exception $e) { + // 忽略错误 + } + return 'unknown'; + } + + /** + * 获取来源类型(手动/自动) + */ + private function getSourceType() + { + // 检查是否为命令行 + if (php_sapi_name() === 'cli') { + return 'auto'; + } + + // 检查调用堆栈,判断是否为自动操作 + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 15); + foreach ($trace as $frame) { + // 如果是 UpdateMenuListener 调用,标记为自动 + if (isset($frame['class']) && strpos($frame['class'], 'UpdateMenuListener') !== false) { + return 'auto'; + } + } + + return 'manual'; + } + + /** + * 获取用户ID + */ + private function getUserId() + { + try { + $user = app('auth')->user(); + if ($user) { + return $user->get('user_id') ?? $user->get('id') ?? null; + } + } catch (\Exception $e) { + // 忽略错误 + } + return null; + } + + /** + * 获取用户名 + */ + private function getUserName() + { + try { + $user = app('auth')->user(); + if ($user) { + return $user->get('user_name') ?? $user->get('name') ?? 'system'; + } + } catch (\Exception $e) { + // 忽略错误 + } + return 'system'; + } + + /** + * 获取用户邮箱 + */ + private function getUserEmail() + { + try { + $user = app('auth')->user(); + if ($user) { + return $user->get('email') ?? null; + } + } catch (\Exception $e) { + // 忽略错误 + } + return null; + } + + /** + * 获取请求数据 + */ + private function getRequestData($data) + { + try { + $request = app('request'); + if ($request) { + return $request->all(); + } + } catch (\Exception $e) { + // 忽略错误 + } + return $data; + } + + /** + * 获取请求IP + */ + private function getRequestIp() + { + try { + $request = app('request'); + if ($request) { + return $request->ip(); + } + } catch (\Exception $e) { + // 忽略错误 + } + return null; + } + + /** + * 获取用户代理 + */ + private function getUserAgent() + { + try { + $request = app('request'); + if ($request) { + return $request->userAgent(); + } + } catch (\Exception $e) { + // 忽略错误 + } + return null; + } + + /** + * 获取追踪ID + */ + private function getTraceId() + { + try { + $request = app('request'); + if ($request) { + return $request->header('X-Trace-Id') ?? uniqid('trace_', true); + } + } catch (\Exception $e) { + // 忽略错误 + } + return uniqid('trace_', true); + } + + /** + * 获取简化的调用堆栈 + */ + private function getSimpleStackTrace() + { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10); + $stack = []; + foreach ($trace as $frame) { + if (isset($frame['class']) && isset($frame['function'])) { + $class = basename(str_replace('\\', '/', $frame['class'])); + $stack[] = $class . '::' . $frame['function'] . '()'; + } + } + return implode(' -> ', array_slice($stack, 0, 5)); + } + + /** + * 获取上下文信息 + */ + private function getContext() + { + $context = [ + 'is_upload' => false, + 'is_migration' => false, + 'json_file' => null, + ]; + + // 检查调用堆栈 + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 15); + foreach ($trace as $frame) { + if (isset($frame['function'])) { + if ($frame['function'] == 'uploadMenus') { + $context['is_upload'] = true; + } + if (isset($frame['class']) && strpos($frame['class'], 'UpdateMenuListener') !== false) { + $context['is_migration'] = true; + } + } + } + + return $context; + } + /** * 获取数据表字段数据 * diff --git a/src/SuperAdminBundle/Services/ShopMenuService.php b/src/SuperAdminBundle/Services/ShopMenuService.php index 6224f7a..04e4f8b 100644 --- a/src/SuperAdminBundle/Services/ShopMenuService.php +++ b/src/SuperAdminBundle/Services/ShopMenuService.php @@ -163,6 +163,11 @@ class ShopMenuService $this->checkParentMenuType($parentTypeList, $menuTypeList); } + // 记录创建时 is_show 为 false 的情况 + if (isset($data['is_show']) && ($data['is_show'] == 'false' || $data['is_show'] == 0)) { + $this->logIsShowChangeToFalseFromCreate($data); + } + $conn = app('registry')->getConnection('default'); $conn->beginTransaction(); try { @@ -294,6 +299,14 @@ class ShopMenuService 'shopmenu_id' => $requestData['shopmenu_id'] ]; + // 记录更新时 is_show 从 true 变为 false 的情况 + if (isset($requestData['is_show']) && ($requestData['is_show'] == 'false' || $requestData['is_show'] == 0)) { + $oldMenu = $this->shopMenuRepository->getInfo(['shopmenu_id' => $requestData['shopmenu_id']]); + if ($oldMenu && $oldMenu['is_show'] === true) { + $this->logIsShowChangeToFalseFromUpdate($requestData, $oldMenu); + } + } + unset($requestData['shopmenu_id']); $conn = app('registry')->getConnection('default'); @@ -384,6 +397,11 @@ class ShopMenuService $insert['is_show'] = $insert['is_show'] == 'false' ? 0 : 1; $insert['disabled'] = $insert['disabled'] == 'true' ? 1 : 0; + // 记录上传导入时 is_show 为 false 的情况 + if ($insert['is_show'] == 0) { + $this->logIsShowChangeToFalseFromUpload($insert, $row, $company_id); + } + if (!$conn->insert('shop_menu', $insert)) { throw new StoreResourceFailedException('导入失败'); } @@ -617,4 +635,341 @@ class ShopMenuService { return $this->shopMenuRepository->$method(...$parameters); } + + /** + * 记录创建时 is_show 为 false 的日志 + * + * @param array $data + */ + private function logIsShowChangeToFalseFromCreate($data) + { + try { + $logData = [ + 'timestamp' => date('Y-m-d H:i:s'), + 'action' => 'create', + 'shopmenu_id' => $data['shopmenu_id'] ?? null, + 'company_id' => $data['company_id'] ?? 0, + 'version' => $data['version'] ?? 1, + 'alias_name' => $data['alias_name'] ?? null, + 'name' => $data['name'] ?? null, + 'old_value' => null, + 'new_value' => false, + 'source' => $this->getRequestSource(), + 'source_type' => $this->getSourceType(), + 'user_id' => $this->getUserId(), + 'user_name' => $this->getUserName(), + 'user_email' => $this->getUserEmail(), + 'request_data' => $this->getRequestData($data), + 'ip' => $this->getRequestIp(), + 'user_agent' => $this->getUserAgent(), + 'trace_id' => $this->getTraceId(), + 'stack_trace' => 'ShopMenuService::create()', + 'context' => [ + 'is_upload' => false, + 'is_migration' => false, + 'json_file' => null, + ], + ]; + + $logFile = storage_path('logs/shopmenu_is_show_hidden.log'); + $logLine = json_encode($logData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n"; + file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX); + } catch (\Exception $e) { + // 记录日志失败不影响主流程,静默处理 + } + } + + /** + * 记录更新时 is_show 从 true 变为 false 的日志 + * + * @param array $requestData + * @param array $oldMenu + */ + private function logIsShowChangeToFalseFromUpdate($requestData, $oldMenu) + { + try { + $logData = [ + 'timestamp' => date('Y-m-d H:i:s'), + 'action' => 'update', + 'shopmenu_id' => $requestData['shopmenu_id'] ?? null, + 'company_id' => $oldMenu['company_id'] ?? 0, + 'version' => $oldMenu['version'] ?? 1, + 'alias_name' => $oldMenu['alias_name'] ?? null, + 'name' => $oldMenu['name'] ?? null, + 'old_value' => true, + 'new_value' => false, + 'source' => $this->getRequestSource(), + 'source_type' => $this->getSourceType(), + 'user_id' => $this->getUserId(), + 'user_name' => $this->getUserName(), + 'user_email' => $this->getUserEmail(), + 'request_data' => $this->getRequestData($requestData), + 'ip' => $this->getRequestIp(), + 'user_agent' => $this->getUserAgent(), + 'trace_id' => $this->getTraceId(), + 'stack_trace' => 'ShopMenuService::updateMenus() -> ShopMenuRepository::updateOneBy()', + 'context' => [ + 'is_upload' => false, + 'is_migration' => false, + 'json_file' => null, + ], + ]; + + $logFile = storage_path('logs/shopmenu_is_show_hidden.log'); + $logLine = json_encode($logData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n"; + file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX); + } catch (\Exception $e) { + // 记录日志失败不影响主流程,静默处理 + } + } + + /** + * 记录上传导入时 is_show 为 false 的日志 + * + * @param array $insert + * @param array $row + * @param int $company_id + */ + private function logIsShowChangeToFalseFromUpload($insert, $row, $company_id = 0) + { + try { + // 检查是否为自动导入(迁移) + $isMigration = $this->isMigrationContext(); + + $logData = [ + 'timestamp' => date('Y-m-d H:i:s'), + 'action' => $isMigration ? 'auto_import' : 'upload', + 'shopmenu_id' => $insert['shopmenu_id'] ?? null, + 'company_id' => $company_id, + 'version' => $insert['version'] ?? 1, + 'alias_name' => $insert['alias_name'] ?? null, + 'name' => $insert['name'] ?? null, + 'old_value' => null, // 上传导入时,旧菜单已被删除,无法获取旧值 + 'new_value' => false, + 'source' => $this->getRequestSource(), + 'source_type' => $isMigration ? 'auto' : 'manual', + 'user_id' => $this->getUserId(), + 'user_name' => $this->getUserName(), + 'user_email' => $this->getUserEmail(), + 'request_data' => $row, + 'ip' => $this->getRequestIp(), + 'user_agent' => $this->getUserAgent(), + 'trace_id' => $this->getTraceId(), + 'stack_trace' => 'ShopMenuService::uploadMenus() -> $conn->insert()', + 'context' => [ + 'is_upload' => true, + 'is_migration' => $isMigration, + 'json_file' => $this->getJsonFileName(), + ], + ]; + + $logFile = storage_path('logs/shopmenu_is_show_hidden.log'); + $logLine = json_encode($logData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n"; + file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX); + } catch (\Exception $e) { + // 记录日志失败不影响主流程,静默处理 + } + } + + /** + * 获取请求来源 + */ + private function getRequestSource() + { + try { + if (php_sapi_name() === 'cli') { + return 'cli'; + } + $request = app('request'); + if ($request) { + return $request->method() . ' ' . $request->path(); + } + } catch (\Exception $e) { + // 忽略错误 + } + return 'unknown'; + } + + /** + * 获取来源类型(手动/自动) + */ + private function getSourceType() + { + // 检查是否为命令行 + if (php_sapi_name() === 'cli') { + return 'auto'; + } + + // 检查调用堆栈,判断是否为自动操作 + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 15); + foreach ($trace as $frame) { + // 如果是 UpdateMenuListener 调用,标记为自动 + if (isset($frame['class']) && strpos($frame['class'], 'UpdateMenuListener') !== false) { + return 'auto'; + } + } + + return 'manual'; + } + + /** + * 检查是否为迁移上下文 + */ + private function isMigrationContext() + { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 15); + foreach ($trace as $frame) { + if (isset($frame['class']) && strpos($frame['class'], 'UpdateMenuListener') !== false) { + return true; + } + } + return false; + } + + /** + * 获取 JSON 文件名 + */ + private function getJsonFileName() + { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 20); + foreach ($trace as $frame) { + if (isset($frame['file'])) { + // 检查是否在 UpdateMenuListener 中 + if (strpos($frame['file'], 'UpdateMenuListener') !== false) { + // 尝试从文件路径推断 JSON 文件名 + if (strpos($frame['file'], 'platform_menu.json') !== false) { + return 'platform_menu.json'; + } + if (strpos($frame['file'], 'it_menu.json') !== false) { + return 'it_menu.json'; + } + if (strpos($frame['file'], 'shop_menu.json') !== false) { + return 'shop_menu.json'; + } + if (strpos($frame['file'], 'dealer_menu.json') !== false) { + return 'dealer_menu.json'; + } + if (strpos($frame['file'], 'merchant_menu.json') !== false) { + return 'merchant_menu.json'; + } + if (strpos($frame['file'], 'supplier_menu.json') !== false) { + return 'supplier_menu.json'; + } + } + } + } + return null; + } + + /** + * 获取用户ID + */ + private function getUserId() + { + try { + $user = app('auth')->user(); + if ($user) { + return $user->get('user_id') ?? $user->get('id') ?? null; + } + } catch (\Exception $e) { + // 忽略错误 + } + return null; + } + + /** + * 获取用户名 + */ + private function getUserName() + { + try { + $user = app('auth')->user(); + if ($user) { + return $user->get('user_name') ?? $user->get('name') ?? 'system'; + } + } catch (\Exception $e) { + // 忽略错误 + } + return 'system'; + } + + /** + * 获取用户邮箱 + */ + private function getUserEmail() + { + try { + $user = app('auth')->user(); + if ($user) { + return $user->get('email') ?? null; + } + } catch (\Exception $e) { + // 忽略错误 + } + return null; + } + + /** + * 获取请求数据 + */ + private function getRequestData($data) + { + try { + $request = app('request'); + if ($request) { + return $request->all(); + } + } catch (\Exception $e) { + // 忽略错误 + } + return $data; + } + + /** + * 获取请求IP + */ + private function getRequestIp() + { + try { + $request = app('request'); + if ($request) { + return $request->ip(); + } + } catch (\Exception $e) { + // 忽略错误 + } + return null; + } + + /** + * 获取用户代理 + */ + private function getUserAgent() + { + try { + $request = app('request'); + if ($request) { + return $request->userAgent(); + } + } catch (\Exception $e) { + // 忽略错误 + } + return null; + } + + /** + * 获取追踪ID + */ + private function getTraceId() + { + try { + $request = app('request'); + if ($request) { + return $request->header('X-Trace-Id') ?? uniqid('trace_', true); + } + } catch (\Exception $e) { + // 忽略错误 + } + return uniqid('trace_', true); + } } diff --git a/src/SupplierBundle/Http/Api/V1/Action/Supplier.php b/src/SupplierBundle/Http/Api/V1/Action/Supplier.php index 9072a73..2388118 100644 --- a/src/SupplierBundle/Http/Api/V1/Action/Supplier.php +++ b/src/SupplierBundle/Http/Api/V1/Action/Supplier.php @@ -98,7 +98,7 @@ class Supplier extends Controller $supplier_name = trim($request->input('supplier_name', '')); $mobile = trim($request->input('mobile', '')); $page = intval($request->input('page', 1)); - $pageSize = intval($request->input('page_size', 20)); + $pageSize = intval($request->input('pageSize', 20)); $filter = []; $filter['company_id'] = $company_id; diff --git a/src/ThirdPartyBundle/Services/Map/MapService.php b/src/ThirdPartyBundle/Services/Map/MapService.php index b25934f..22113ed 100644 --- a/src/ThirdPartyBundle/Services/Map/MapService.php +++ b/src/ThirdPartyBundle/Services/Map/MapService.php @@ -220,6 +220,10 @@ class MapService extends BaseService return (new RedisCacheService($companyId, "map_default_info", 60))->getByPrevention(function () use ($companyId) { $defaultInfo = $this->getRepository()->getInfo(["company_id" => $companyId, "is_default" => self::DEFAULT_YES]); if (empty($defaultInfo)) { + //app_key、app_secret为空,不插入,避免报错 + if (empty(config("common.map.amap.app_key", "")) || empty(config("common.map.amap.app_secret", ""))) { + return []; + } $defaultInfo = $this->create([ "company_id" => $companyId, "type" => self::TYPE_AMAP, diff --git a/src/WechatBundle/Http/Api/V1/Action/CustomizePage.php b/src/WechatBundle/Http/Api/V1/Action/CustomizePage.php index 5eccf89..9e8f6f0 100644 --- a/src/WechatBundle/Http/Api/V1/Action/CustomizePage.php +++ b/src/WechatBundle/Http/Api/V1/Action/CustomizePage.php @@ -82,13 +82,17 @@ class CustomizePage extends Controller $params['is_open'] = (isset($params['is_open']) && (($params['is_open'] === "false" || $params['is_open'] === false || $params['is_open'] === 0 || $params['is_open'] === '0'))) ? false : true; $companyId = app('auth')->user()->get('company_id'); $params['company_id'] = $companyId; - if ($params['is_open'] == 1 || $params['is_open'] == true || $params['is_open'] == '1' || $params['is_open'] == 'true') { + // 只有当page_type为"my"且is_open为1时,才校验"只能开启一个"的规则 + if (($params['is_open'] == 1 || $params['is_open'] == true || $params['is_open'] == '1' || $params['is_open'] == 'true') + && isset($params['page_type']) && $params['page_type'] === 'my') { $cfilter['is_open'] = 1; $cfilter['company_id'] = $companyId; - $cfilter['page_type'] = $params['page_type']; - $cfilter['template_name'] = $params['template_name']; + $cfilter['page_type'] = 'my'; + // 限制相同的template_name,与列表接口保持一致 + if (isset($params['template_name']) && $params['template_name'] !== '') { + $cfilter['template_name'] = $params['template_name']; + } $count = $this->CustomizePageService->count($cfilter); - app('log')->info(__FUNCTION__.':'.__LINE__.':count:'.json_encode($count)); if ($count > 0) { return $this->response->array(['status' => false, 'message' => "已经有启用的模版", 'status_code' => 422]); } @@ -144,16 +148,39 @@ class CustomizePage extends Controller $filter['id'] = $id; $filter['company_id'] = $companyId; - if ($params['is_open'] == 1 || $params['is_open'] == true || $params['is_open'] == '1' || $params['is_open'] == 'true') { - $page_type = $request->input('page_type', 'my'); - $cfilter['is_open'] = 1; - $cfilter['id'] = ['!=', $id]; - $cfilter['company_id'] = $companyId; - $cfilter['page_type'] = $page_type; - $cfilter['template_name'] = $params['template_name']; - $count = $this->CustomizePageService->count($cfilter); - if ($count > 0) { - return $this->response->array(['status' => false, 'message' => "已经有启用的模版", 'status_code' => 422]); + // 只有当page_type为"my"且is_open为1时,才校验"只能开启一个"的规则 + if (($params['is_open'] == 1 || $params['is_open'] == true || $params['is_open'] == '1' || $params['is_open'] == 'true')) { + // 先获取当前记录的完整信息 + $currentPage = $this->CustomizePageService->getInfoById($id); + if (!$currentPage) { + throw new ResourceException("自定义页面不存在"); + } + // 获取page_type(优先从请求中获取,否则从数据库读取) + $page_type = $request->input('page_type'); + if (empty($page_type)) { + $page_type = $currentPage['page_type'] ?? null; + } + // 只有当page_type为"my"时,才进行校验 + if ($page_type === 'my') { + // 如果当前记录本身就是开启的,允许保持开启状态 + $currentIsOpen = isset($currentPage['is_open']) && ($currentPage['is_open'] == 1 || $currentPage['is_open'] == true || $currentPage['is_open'] == '1'); + if (!$currentIsOpen) { + // 当前记录是关闭的,要开启它时,检查是否有其他开启的记录(限制相同的template_name) + $cfilter['is_open'] = 1; + $cfilter['id'] = ['!=', $id]; + $cfilter['company_id'] = $companyId; + $cfilter['page_type'] = 'my'; + // 限制相同的template_name,与列表接口保持一致 + if (isset($params['template_name']) && $params['template_name'] !== '') { + $cfilter['template_name'] = $params['template_name']; + } elseif (isset($currentPage['template_name']) && $currentPage['template_name'] !== '') { + $cfilter['template_name'] = $currentPage['template_name']; + } + $count = $this->CustomizePageService->count($cfilter); + if ($count > 0) { + return $this->response->array(['status' => false, 'message' => "已经有启用的模版", 'status_code' => 422]); + } + } } } @@ -196,6 +223,20 @@ class CustomizePage extends Controller * required=false, * type="string" * ), + * @SWG\Parameter( + * name="is_open", + * in="query", + * description="是否开启 1:开启 0:关闭", + * required=false, + * type="integer" + * ), + * @SWG\Parameter( + * name="page_name", + * in="query", + * description="页面名称(支持模糊查询)", + * required=false, + * type="string" + * ), * @SWG\Response( response=200, description="成功返回结构", @SWG\Schema( * @SWG\Property( property="data", type="object", * @SWG\Property( property="total_count", type="string", example="20"), @@ -219,7 +260,7 @@ class CustomizePage extends Controller */ public function getCustomizepageList(Request $request) { - $params = $request->all('template_name', 'page', 'pageSize', 'page_type'); + $params = $request->all('template_name', 'page', 'pageSize', 'page_type', 'is_open', 'page_name'); $page = $params['page'] ? intval($params['page']) : 1; $pageSize = $params['pageSize'] ? intval($params['pageSize']) : $this->limit; @@ -227,9 +268,17 @@ class CustomizePage extends Controller $filter['company_id'] = $companyId; $filter['template_name'] = $params['template_name']; $params['page_type'] = $params['page_type'] ? $params['page_type'] : 'normal'; + // is_open 参数:不传时查全部,传了再使用传入的值查询 + if (isset($params['is_open']) && $params['is_open'] !== '' && $params['is_open'] !== null) { + $filter['is_open'] = intval($params['is_open']); + } if ($params['page_type']) { $filter['page_type'] = $params['page_type']; } + // page_name 参数:支持模糊查询 + if (isset($params['page_name']) && $params['page_name'] !== '' && $params['page_name'] !== null) { + $filter['page_name|contains'] = $params['page_name']; + } $orderBy = ['id' => 'DESC']; $result = $this->CustomizePageService->lists($filter, "*", $page, $pageSize, $orderBy); return $this->response->array($result); diff --git a/src/WsugcBundle/Repositories/PostRepository.php b/src/WsugcBundle/Repositories/PostRepository.php index ac28e7e..2ae2fe7 100755 --- a/src/WsugcBundle/Repositories/PostRepository.php +++ b/src/WsugcBundle/Repositories/PostRepository.php @@ -34,7 +34,7 @@ class PostRepository extends EntityRepository public $module = 'wsugc_post'; // 多语言对应的模块 public $primaryKey = 'post_id'; // 主键,对应data_id public $langField = [ - 'title','address','topics','content','ai_refuse_reason','manual_refuse_reason' + 'title','address','content','ai_refuse_reason','manual_refuse_reason' ]; // 多语言字段 public function getEntity() diff --git a/src/WsugcBundle/Services/PostService.php b/src/WsugcBundle/Services/PostService.php index b9590e8..48d4e22 100755 --- a/src/WsugcBundle/Services/PostService.php +++ b/src/WsugcBundle/Services/PostService.php @@ -170,10 +170,10 @@ class PostService if($v['topics']){ $topicService=new TopicService(); if(!$fromAdmin){ - $filterTopics=['topic_id'=>$v['topics'],'status'=>1]; + $filterTopics=['topic_id'=>$v['topics'],'status'=>1,'company_id'=>$v['company_id']]; } else{ - $filterTopics=['topic_id'=>$v['topics']]; + $filterTopics=['topic_id'=>$v['topics'],'company_id'=>$v['company_id']]; } $itemList=$topicService->getTopicList($filterTopics,'topic_id,topic_name,status,created'); $v['topics']=$itemList['list']??[];