diff --git a/.env.example b/.env.example index 75da312..35ae32a 100644 --- a/.env.example +++ b/.env.example @@ -47,16 +47,29 @@ MAIL_PASSWORD= MAIL_FROM_ADDRESS= MAIL_FROM_NAME= -# 微信小程序(code2session 换取 openid,在线支付必需) +# 微信小程序(code2session 换取 openid,在线支付必需;也可在后台 系统设置→微信应用配置 维护,后台配置优先) WECHAT_MINI_APPID= WECHAT_MINI_SECRET= -# 旺铺支付网关(也可在后台 系统设置→支付配置 中维护,后台配置优先) +# 在线支付渠道开关:wangpu=旺铺支付网关 / wechat=微信官方支付(后台 系统设置→支付配置 优先) +PAY_ONLINE_CHANNEL=wangpu + +# 旺铺支付网关(也可在后台 系统设置→旺铺支付 中维护,后台配置优先) WANGPU_BASE_URL= WANGPU_ORGANIZ_NO= WANGPU_MER_NO= WANGPU_MER_CODE= WANGPU_TERM_CODE= -WANGPU_SIGN_KEY= +WANGPU_PUBLIC_KEY= +WANGPU_PRIVATE_KEY= WANGPU_SUB_APPID= WANGPU_PAYWAY_CODE=WECHAT_MINI + +# 微信官方支付 APIv3(也可在后台 系统设置→微信官方支付 中维护,后台配置优先) +WXPAY_MCH_ID= +WXPAY_APPID= +WXPAY_PRIVATE_KEY= +WXPAY_CERTIFICATE= +WXPAY_SECRET_KEY= +WXPAY_PLATFORM_CERT= +WXPAY_PLATFORM_SERIAL= diff --git a/.phpunit.result.cache b/.phpunit.result.cache index d21ef37..977de0c 100644 --- a/.phpunit.result.cache +++ b/.phpunit.result.cache @@ -1 +1 @@ -{"version":2,"defects":{"Tests\\Feature\\ProductPriceTest::test_product_list_returns_price_for_store_level":8,"Tests\\Feature\\ProductPriceTest::test_store_without_level_is_rejected":8,"Tests\\Feature\\ProductPriceTest::test_batch_price_updates_and_notifies_affected_stores":7,"Tests\\Feature\\ProductPriceTest::test_price_matrix_structure":8,"Tests\\Feature\\StoreOrderTest::test_place_order_snapshots_level_price_and_recalculates":8,"Tests\\Feature\\StoreOrderTest::test_client_supplied_amount_is_ignored":8,"Tests\\Feature\\StoreOrderTest::test_product_without_level_price_rejected":8,"Tests\\Feature\\StoreOrderTest::test_cancel_only_pending_orders":8,"Tests\\Feature\\StoreOrderTest::test_summarized_order_cannot_be_cancelled":8,"Tests\\Feature\\StoreOrderTest::test_order_data_isolated_between_stores":8,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_orders_by_product":7,"Tests\\Feature\\PurchaseGenerateTest::test_generate_writes_back_order_status":7,"Tests\\Feature\\PurchaseGenerateTest::test_generate_without_pending_orders_fails":8,"Tests\\Feature\\PurchaseGenerateTest::test_generate_is_idempotent":7,"Tests\\Feature\\AllocationTest::test_allocation_conserves_amount_with_tail_correction":7,"Tests\\Feature\\AllocationTest::test_allocation_follows_order_ratio":7,"Tests\\Feature\\AllocationTest::test_allocation_is_idempotent":7,"Tests\\Feature\\AllocationTest::test_allocation_rejected_without_actual_amount":8,"Tests\\Feature\\MiniAuthTest::test_login_creates_user_and_issues_token":7,"Tests\\Feature\\MiniAuthTest::test_phone_binding_matches_store":8,"Tests\\Feature\\MiniAuthTest::test_phone_no_match_stays_pending":8,"Tests\\Feature\\ExportTest::test_export_xlsx_with_encoded_chinese_filename":7,"Tests\\Feature\\CartTest::test_list_with_prices_amounts_and_totals":7,"Tests\\Feature\\CartTest::test_list_marks_off_shelf_item_unbuyable":7,"Tests\\Feature\\DebugCartListTest::test_dump_cart_list_response":5,"Tests\\Feature\\ProductCostPriceTest::test_create_product_with_cost_and_percent_pricing":7,"Tests\\Feature\\ProductCostPriceTest::test_create_percent_row_without_percent_fails":7,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_cost_only_notifies_percent_level_stores":7,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_empty_row_rejected":7,"Tests\\Feature\\MiniAuthTest::test_disabled_user_cannot_login":8,"Tests\\Feature\\MiniAuthTest::test_mini_token_cannot_access_admin_api":8,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_percent_row_update":7,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_mixed_row_updates_cost_and_level":7,"Tests\\Feature\\ReconciliationTest::test_build_creates_reconciliation_items":8,"Tests\\Feature\\ReconciliationTest::test_build_filters_by_supplier":8,"Tests\\Feature\\ReconciliationTest::test_update_item_recalculates_diff_and_header":8,"Tests\\Feature\\ReconciliationTest::test_toggle_reconciled_flag":8,"Tests\\Feature\\ReconciliationTest::test_settle_creates_settlements_per_store":8,"Tests\\Feature\\ProductCostPriceTest::test_mini_list_returns_actual_price_without_cost_price":8,"Tests\\Feature\\ProductCostPriceTest::test_mini_order_uses_actual_price_for_percent_row":8,"Tests\\Feature\\ProductCostPriceTest::test_mini_cart_uses_actual_price_for_percent_row":8,"Tests\\Feature\\StoreOrderTest::test_container_update_recalculates_amounts":8,"Tests\\Feature\\StoreOrderTest::test_container_update_allowed_in_editable_statuses":8,"Tests\\Feature\\StoreOrderTest::test_container_update_rejected_in_other_statuses":8,"Tests\\Feature\\StoreOrderTest::test_container_update_heals_legacy_product_amount":8,"Tests\\Feature\\StoreOrderTest::test_container_update_validates_negative_numbers":8,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_rejected_when_product_deleted":7,"Tests\\Feature\\StoreOrderItemTest::test_order_list_search_by_product_name":8,"Tests\\Feature\\PurchaseEditTest::test_detail_returns_store_matrix":7,"Tests\\Feature\\PurchaseEditTest::test_update_cell_syncs_order_item_and_totals":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_syncs_all_order_items":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_weight_distributed_by_quantity":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_product_attributes":7,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_order_items_into_header":7,"Tests\\Feature\\ExportTest::test_export_category_filters_to_vegetables":7,"Tests\\Feature\\ExportTest::test_export_pdf":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_does_not_touch_manual_weight":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_to_product_catalog":7,"Tests\\Feature\\PurchaseEditTest::test_update_cell_weight_cascades_totals":7,"Tests\\Feature\\PurchaseEditTest::test_cell_sync_refreshes_snapshot_and_cascades":7,"Tests\\Feature\\PurchaseEditTest::test_edits_rejected_when_purchase_completed":7,"Tests\\Feature\\StoreOrderItemTest::test_update_item_recalculates_order_totals":7,"Tests\\Feature\\StoreOrderItemTest::test_update_item_validates_negative_price":7,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_updates_snapshot_from_product":7,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_recalculates_percent_price_with_latest_cost":7,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_returns_items_with_order_info":8,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_leaf_category_ok":7,"Tests\\Feature\\BillExportTest::test_export_filters_by_root_category":8,"Tests\\Feature\\BillExportTest::test_export_requires_export_permission":8,"Tests\\Feature\\DebugPermissionTest::test_debug_permission":8,"Tests\\Feature\\BillPaymentTest::test_order_status_progresses_via_business_chain":7,"Tests\\Feature\\BillPaymentTest::test_payment_audit_reject_does_not_accumulate":7,"Tests\\Feature\\BillPaymentTest::test_payment_detail_returns_voucher_urls":8,"Tests\\Feature\\ContainerReturnTest::test_press_containers_adds_amount_and_writes_record":7,"Tests\\Feature\\ContainerReturnTest::test_return_containers_deducts_amount":7,"Tests\\Feature\\ContainerReturnTest::test_mixed_sign_containers":7,"Tests\\Feature\\ContainerReturnTest::test_zero_containers_writes_no_record":7,"Tests\\Feature\\StoreOrderTest::test_order_list_outputs_status_name_and_item_preview":7,"Tests\\Feature\\DashboardTest::test_requires_dashboard_analysis_ability":7,"Tests\\Feature\\DashboardTest::test_recon_summary_and_receivable":8,"Tests\\Feature\\DashboardDebugTest::test_debug":8,"Tests\\Feature\\StoreOrderItemTest::test_place_order_snapshots_full_product_info":8,"Tests\\Feature\\StoreOrderItemTest::test_mini_detail_hides_cost_price":8,"Tests\\Feature\\StoreOrderItemTest::test_admin_detail_shows_cost_price_and_supplier":8,"Tests\\Feature\\StoreOrderItemTest::test_update_item_rejected_when_completed_or_cancelled":8,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_uses_level_percent_price":8,"Tests\\Feature\\ExportTest::test_export_suppliers_multi_sheet":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_skips_catalog_sync_when_product_deleted":7,"Tests\\Feature\\ProductImportExportTest::test_export_filters_by_category":8,"Tests\\Feature\\ProductImportExportTest::test_import_creates_products_and_auto_supplier":7,"Tests\\Feature\\ProductImportExportTest::test_import_matches_existing_supplier":7,"Tests\\Feature\\ProductImportExportTest::test_import_errors_abort_all_rows":7,"Tests\\Feature\\ProductImportExportTest::test_import_category_path_resolution":7,"Tests\\Feature\\MiniReportTest::test_report_accumulates_same_product_across_orders":7,"Tests\\Feature\\ExportTest::test_export_suppliers_split_by_market":7,"Tests\\Feature\\MiniOnlinePaymentTest::test_query_syncs_gateway_status":7,"Tests\\Feature\\MiniSpecialTest::test_cart_quantity_attached_for_store":8,"Tests\\Feature\\MiniWechatPaymentTest::test_create_wechat_payment_success":7,"Tests\\Feature\\ExportTest::test_export_lists_all_catalog_products_with_totals_row":7},"times":{"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.004,"Tests\\Feature\\ProductPriceTest::test_product_list_returns_price_for_store_level":0.088,"Tests\\Feature\\ProductPriceTest::test_store_without_level_is_rejected":0.007,"Tests\\Feature\\ProductPriceTest::test_batch_price_updates_and_notifies_affected_stores":0.01,"Tests\\Feature\\ProductPriceTest::test_price_matrix_structure":0.007,"Tests\\Feature\\StoreOrderTest::test_place_order_snapshots_level_price_and_recalculates":0.048,"Tests\\Feature\\StoreOrderTest::test_client_supplied_amount_is_ignored":0.048,"Tests\\Feature\\StoreOrderTest::test_product_without_level_price_rejected":0.007,"Tests\\Feature\\StoreOrderTest::test_cancel_only_pending_orders":0.051,"Tests\\Feature\\StoreOrderTest::test_summarized_order_cannot_be_cancelled":0.051,"Tests\\Feature\\StoreOrderTest::test_order_data_isolated_between_stores":0.092,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_orders_by_product":0.028,"Tests\\Feature\\PurchaseGenerateTest::test_generate_writes_back_order_status":0.101,"Tests\\Feature\\PurchaseGenerateTest::test_generate_without_pending_orders_fails":0.006,"Tests\\Feature\\PurchaseGenerateTest::test_generate_is_idempotent":0.1,"Tests\\Feature\\AllocationTest::test_allocation_conserves_amount_with_tail_correction":0.076,"Tests\\Feature\\AllocationTest::test_allocation_follows_order_ratio":0.022,"Tests\\Feature\\AllocationTest::test_allocation_is_idempotent":0.028,"Tests\\Feature\\AllocationTest::test_allocation_rejected_without_actual_amount":0.021,"Tests\\Feature\\DebugGenerateTest::test_debug_generate":0.047,"Tests\\Feature\\ReconciliationTest::test_build_creates_reconciliation_items":0.019,"Tests\\Feature\\ReconciliationTest::test_build_filters_by_supplier":0.022,"Tests\\Feature\\ReconciliationTest::test_update_item_recalculates_diff_and_header":0.019,"Tests\\Feature\\ReconciliationTest::test_toggle_reconciled_flag":0.02,"Tests\\Feature\\ReconciliationTest::test_settle_creates_settlements_per_store":0.036,"Tests\\Feature\\StatementTest::test_generate_snapshots_payment_cycle":0.011,"Tests\\Feature\\StatementTest::test_statement_isolated_between_stores":0.013,"Tests\\Feature\\StatementTest::test_generate_excludes_cancelled_and_used_items":0.016,"Tests\\Feature\\MiniAuthTest::test_login_creates_user_and_issues_token":0.056,"Tests\\Feature\\MiniAuthTest::test_disabled_user_cannot_login":0.003,"Tests\\Feature\\MiniAuthTest::test_phone_binding_matches_store":0.005,"Tests\\Feature\\MiniAuthTest::test_phone_no_match_stays_pending":0.001,"Tests\\Feature\\MiniAuthTest::test_sys_token_cannot_access_mini":0.005,"Tests\\Feature\\MiniAuthTest::test_mini_token_cannot_access_admin_api":0.047,"Tests\\Feature\\ExportTest::test_export_xlsx_with_encoded_chinese_filename":0.144,"Tests\\Feature\\ExportTest::test_export_category_filters_to_vegetables":0.017,"Tests\\Feature\\ExportTest::test_export_pdf":0.015,"Tests\\Feature\\ExportTest::test_export_invalid_format_rejected":0.016,"Tests\\Feature\\ExportTest::test_export_requires_export_permission":0.057,"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.001,"Tests\\Feature\\MiniAuthTest::test_login_fails_when_wechat_rejects_code":0.003,"Tests\\Feature\\CartTest::test_add_to_cart_succeeds":0.048,"Tests\\Feature\\CartTest::test_duplicate_add_merges_quantity":0.049,"Tests\\Feature\\CartTest::test_off_shelf_product_rejected":0.046,"Tests\\Feature\\CartTest::test_soft_deleted_product_rejected":0.008,"Tests\\Feature\\CartTest::test_product_without_level_price_rejected":0.006,"Tests\\Feature\\CartTest::test_unbound_user_rejected":0.006,"Tests\\Feature\\CartTest::test_store_without_level_rejected":0.086,"Tests\\Feature\\CartTest::test_list_with_prices_amounts_and_totals":0.051,"Tests\\Feature\\CartTest::test_list_marks_off_shelf_item_unbuyable":0.05,"Tests\\Feature\\CartTest::test_empty_cart_returns_empty_items":0.045,"Tests\\Feature\\CartTest::test_update_quantity":0.05,"Tests\\Feature\\CartTest::test_update_other_users_item_rejected":0.009,"Tests\\Feature\\CartTest::test_update_missing_item_rejected":0.048,"Tests\\Feature\\CartTest::test_invalid_quantity_rejected":0.046,"Tests\\Feature\\CartTest::test_delete_item":0.048,"Tests\\Feature\\CartTest::test_delete_other_users_item_rejected":0.009,"Tests\\Feature\\CartTest::test_clear_only_own_cart":0.093,"Tests\\Feature\\CartTest::test_unauthenticated_returns_401":0.002,"Tests\\Feature\\CartTest::test_cart_isolated_between_users":0.011,"Tests\\Feature\\DebugCartListTest::test_dump_cart_list_response":0.057,"Tests\\Feature\\ProductCostPriceTest::test_calc_actual_price_fixed_and_percent":0.001,"Tests\\Feature\\ProductCostPriceTest::test_calc_actual_price_edge_cases":0.001,"Tests\\Feature\\ProductCostPriceTest::test_admin_list_contains_cost_price_and_actual_price":0.009,"Tests\\Feature\\ProductCostPriceTest::test_mini_list_returns_actual_price_without_cost_price":0.046,"Tests\\Feature\\ProductCostPriceTest::test_create_product_with_cost_and_percent_pricing":0.008,"Tests\\Feature\\ProductCostPriceTest::test_create_percent_row_without_percent_fails":0.007,"Tests\\Feature\\ProductCostPriceTest::test_update_switches_fixed_to_percent":0.01,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_cost_only_notifies_percent_level_stores":0.01,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_percent_row_update":0.009,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_mixed_row_updates_cost_and_level":0.008,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_empty_row_rejected":0.007,"Tests\\Feature\\ProductCostPriceTest::test_price_matrix_includes_cost_and_percent_columns":0.007,"Tests\\Feature\\ProductCostPriceTest::test_mini_order_uses_actual_price_for_percent_row":0.007,"Tests\\Feature\\ProductCostPriceTest::test_mini_cart_uses_actual_price_for_percent_row":0.01,"Tests\\Feature\\PurchaseGenerateTest::test_generate_uses_min_actual_price_across_types":0.014,"Tests\\Feature\\ProductPriceTest::test_store_without_level_sees_products_without_price":0.045,"Tests\\Feature\\ProductPriceTest::test_unbound_user_can_browse_products_without_price_but_cannot_cart":0.009,"Tests\\Feature\\MiniAuthTest::test_login_issues_token_for_registered_user":0.01,"Tests\\Feature\\MiniAuthTest::test_login_rejects_unregistered_openid":0.002,"Tests\\Feature\\MiniAuthTest::test_register_binds_store_and_issues_token":0.009,"Tests\\Feature\\MiniAuthTest::test_register_rejects_unknown_store":0.002,"Tests\\Feature\\MiniAuthTest::test_register_rejects_duplicate_openid":0.003,"Tests\\Feature\\MiniStoreTest::test_info_returns_bound_store":0.005,"Tests\\Feature\\MiniStoreTest::test_update_info":0.045,"Tests\\Feature\\MiniStoreTest::test_update_info_ignores_readonly_fields":0.045,"Tests\\Feature\\MiniStoreTest::test_requires_bound_store":0.007,"Tests\\Feature\\MiniStoreTest::test_update_info_validates_length":0.045,"Tests\\Feature\\StoreOrderTest::test_container_update_recalculates_amounts":0.012,"Tests\\Feature\\StoreOrderTest::test_container_update_allowed_in_editable_statuses":0.022,"Tests\\Feature\\StoreOrderTest::test_container_update_rejected_in_other_statuses":0.019,"Tests\\Feature\\StoreOrderTest::test_container_update_heals_legacy_product_amount":0.02,"Tests\\Feature\\StoreOrderTest::test_container_update_validates_negative_numbers":0.014,"Tests\\Feature\\PurchaseGenerateTest::test_generate_without_accepted_orders_fails":0.054,"Tests\\Feature\\PurchaseGenerateTest::test_generate_with_selected_order_ids":0.103,"Tests\\Feature\\StoreOrderItemTest::test_place_order_snapshots_full_product_info":0.049,"Tests\\Feature\\StoreOrderItemTest::test_mini_detail_hides_cost_price":0.05,"Tests\\Feature\\StoreOrderItemTest::test_admin_detail_shows_cost_price_and_supplier":0.053,"Tests\\Feature\\StoreOrderItemTest::test_update_item_recalculates_order_totals":0.011,"Tests\\Feature\\StoreOrderItemTest::test_update_item_rejected_when_completed_or_cancelled":0.011,"Tests\\Feature\\StoreOrderItemTest::test_update_item_validates_negative_price":0.012,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_updates_snapshot_from_product":0.013,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_recalculates_percent_price_with_latest_cost":0.01,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_rejected_when_product_deleted":0.01,"Tests\\Feature\\StoreOrderItemTest::test_order_list_search_by_product_name":0.062,"Tests\\Feature\\StoreOrderTest::test_soft_delete_only_cancelled_orders":0.061,"Tests\\Feature\\StoreOrderTest::test_soft_delete_rejected_for_non_cancelled_orders":0.248,"Tests\\Feature\\StoreOrderTest::test_soft_delete_twice_rejected":0.054,"Tests\\Feature\\PurchaseEditTest::test_detail_returns_store_matrix":0.106,"Tests\\Feature\\PurchaseEditTest::test_update_cell_syncs_order_item_and_totals":0.102,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_syncs_all_order_items":0.105,"Tests\\Feature\\PurchaseEditTest::test_update_row_weight_distributed_by_quantity":0.032,"Tests\\Feature\\PurchaseEditTest::test_update_row_requires_at_least_one_field":0.101,"Tests\\Feature\\PurchaseEditTest::test_update_cell_rejects_negative_quantity":0.1,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_order_items_into_header":0.1,"Tests\\Feature\\ReconciliationTest::test_build_excludes_unfinished_orders":0.016,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_product_attributes":0.105,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_to_product_catalog":0.019,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_returns_items_with_order_info":0.103,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_rejects_missing_params":0.101,"Tests\\Feature\\PurchaseEditTest::test_update_cell_weight_cascades_totals":0.103,"Tests\\Feature\\PurchaseEditTest::test_cell_sync_refreshes_snapshot_and_cascades":0.012,"Tests\\Feature\\PurchaseEditTest::test_edits_rejected_when_purchase_completed":0.11,"Tests\\Feature\\PurchaseEditTest::test_update_row_does_not_touch_manual_weight":0.109,"Tests\\Feature\\PurchaseEditTest::test_store_summary_returns_aggregated_items":0.103,"Tests\\Feature\\PurchaseEditTest::test_store_summary_aggregates_multiple_orders_with_weighted_price":0.06,"Tests\\Feature\\PurchaseEditTest::test_store_summary_rejects_missing_or_invalid_params":0.102,"Tests\\Feature\\ExportTest::test_export_invalid_type_rejected":0.016,"Tests\\Feature\\ExportTest::test_export_missing_purchase_rejected":0.007,"Tests\\Feature\\PurchaseEditTest::test_detail_returns_container_summary":0.022,"Tests\\Feature\\PurchaseEditTest::test_update_container_syncs_order_amounts":0.018,"Tests\\Feature\\PurchaseEditTest::test_update_container_rejected_when_purchase_completed":0.018,"Tests\\Feature\\PurchaseEditTest::test_update_container_rejects_incomplete_or_foreign_orders":0.026,"Tests\\Feature\\PurchaseEditTest::test_update_container_validates_negative_and_duplicate_orders":0.018,"Tests\\Feature\\ProductCategoryTest::test_create_child_category_under_top_level":0.006,"Tests\\Feature\\ProductCategoryTest::test_create_category_under_second_level_rejected":0.007,"Tests\\Feature\\ProductCategoryTest::test_update_second_level_move_to_another_top":0.007,"Tests\\Feature\\ProductCategoryTest::test_update_parent_with_children_cannot_move_under_category":0.007,"Tests\\Feature\\ProductCategoryTest::test_update_with_missing_parent_rejected":0.006,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_parent_category_rejected":0.008,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_leaf_category_ok":0.007,"Tests\\Feature\\ProductCategoryTest::test_mini_categories_returns_all_enabled_categories":0.045,"Tests\\Feature\\MiniBillTest::test_bill_list_derives_pay_state_and_settlement_date":0.048,"Tests\\Feature\\MiniBillTest::test_bill_list_summary_aggregates_unpaid":0.047,"Tests\\Feature\\MiniBillTest::test_bill_list_payable_filter":0.047,"Tests\\Feature\\MiniBillTest::test_bill_list_filters_by_bill_date_range":0.068,"Tests\\Feature\\MiniBillTest::test_bill_data_isolated_between_stores":0.088,"Tests\\Feature\\MiniBillTest::test_bill_detail_outputs_bill_items_and_orders":0.049,"Tests\\Feature\\StoreOrderTest::test_order_list_outputs_status_name_and_item_preview":0.053,"Tests\\Feature\\StoreOrderTest::test_order_list_filters_by_order_date_range":0.06,"Tests\\Feature\\StoreOrderTest::test_order_list_rejects_invalid_filters":0.049,"Tests\\Feature\\BillExportTest::test_export_merges_items_across_bills":0.054,"Tests\\Feature\\BillExportTest::test_export_filters_by_root_category":0.051,"Tests\\Feature\\BillExportTest::test_export_empty_category_rejected":0.049,"Tests\\Feature\\BillExportTest::test_export_requires_export_permission":0.051,"Tests\\Feature\\BillExportTest::test_export_invalid_ids_rejected":0.011,"Tests\\Feature\\DebugPermissionTest::test_debug_permission":0.098,"Tests\\Feature\\BillExportTest::test_mini_export_scoped_to_bound_store":0.014,"Tests\\Feature\\BillExportTest::test_mini_export_requires_store_binding":0.005,"Tests\\Feature\\MiniNoticeTest::test_notice_list_includes_personal_and_broadcast":0.051,"Tests\\Feature\\MiniNoticeTest::test_broadcast_read_creates_personal_copy":0.048,"Tests\\Feature\\MiniNoticeTest::test_personal_notice_read_marks_directly":0.046,"Tests\\Feature\\MiniNoticeTest::test_other_users_notice_not_found":0.007,"Tests\\Feature\\StoreOrderTest::test_manual_status_flow_only_accept_and_cancel":0.103,"Tests\\Feature\\StoreOrderTest::test_manual_status_flow_rejects_delivery_and_completion":0.151,"Tests\\Feature\\StoreOrderTest::test_batch_status_only_accept_and_cancel":0.102,"Tests\\Feature\\BillPaymentTest::test_order_status_progresses_via_business_chain":0.062,"Tests\\Feature\\BillPaymentTest::test_manual_pay_accumulates_store_total_purchase_amount":0.068,"Tests\\Feature\\BillPaymentTest::test_payment_audit_pass_accumulates_store_total_purchase_amount":0.053,"Tests\\Feature\\BillPaymentTest::test_payment_audit_reject_does_not_accumulate":0.048,"Tests\\Feature\\MiniProductTest::test_product_detail_guest_sees_null_price":0.045,"Tests\\Feature\\MiniProductTest::test_product_detail_store_user_sees_level_price":0.006,"Tests\\Feature\\MiniProductTest::test_product_detail_percent_price_calculated_from_cost":0.046,"Tests\\Feature\\MiniProductTest::test_product_detail_off_shelf_or_missing_rejected":0.046,"Tests\\Feature\\MiniProductTest::test_product_list_store_user_sees_level_price":0.005,"Tests\\Feature\\MiniProductTest::test_product_list_guest_sees_null_price":0.044,"Tests\\Feature\\BillPaymentTest::test_admin_order_list_and_detail_show_bill_info":0.073,"Tests\\Feature\\BillPaymentTest::test_payment_detail_returns_voucher_urls":0.061,"Tests\\Feature\\StoreOrderTest::test_order_list_preview_includes_image_spec_and_unit":0.05,"Tests\\Feature\\ContainerReturnTest::test_press_containers_adds_amount_and_writes_record":0.06,"Tests\\Feature\\ContainerReturnTest::test_return_containers_deducts_amount":0.059,"Tests\\Feature\\ContainerReturnTest::test_mixed_sign_containers":0.06,"Tests\\Feature\\ContainerReturnTest::test_zero_containers_writes_no_record":0.06,"Tests\\Feature\\ContainerReturnTest::test_non_integer_containers_rejected":0.048,"Tests\\Feature\\ContainerReturnTest::test_manual_create_and_delete_routes_removed":0.007,"Tests\\Feature\\ContainerReturnTest::test_export_matrix_merges_same_day_and_zero_fills":0.091,"Tests\\Feature\\ContainerReturnTest::test_export_filters_by_selected_stores":0.132,"Tests\\Feature\\ContainerReturnTest::test_export_invalid_params_rejected":0.022,"Tests\\Feature\\ContainerReturnTest::test_export_empty_range_rejected":0.008,"Tests\\Feature\\ContainerReturnTest::test_export_requires_export_permission":0.006,"Tests\\Feature\\DashboardTest::test_guest_cannot_access_dashboard":0.002,"Tests\\Feature\\DashboardTest::test_requires_dashboard_analysis_ability":0.006,"Tests\\Feature\\DashboardTest::test_empty_database_returns_zero_structure":0.01,"Tests\\Feature\\DashboardTest::test_overview_excludes_cancelled_orders":0.05,"Tests\\Feature\\DashboardTest::test_week_growth_rate":0.055,"Tests\\Feature\\DashboardTest::test_trend_covers_30_days_with_zero_filling":0.051,"Tests\\Feature\\DashboardTest::test_category_sales_grouped_by_category":0.053,"Tests\\Feature\\DashboardTest::test_top_products_aggregated_across_orders":0.051,"Tests\\Feature\\DashboardTest::test_top_stores_ranked_by_amount":0.092,"Tests\\Feature\\DashboardTest::test_purchase_amount_prefers_actual_over_estimate":0.009,"Tests\\Feature\\DashboardTest::test_recon_summary_and_receivable":0.051,"Tests\\Feature\\DashboardTest::test_latest_orders_limited_and_ordered":0.052,"Tests\\Feature\\DashboardTest::test_archives_count_active_records_only":0.133,"Tests\\Feature\\DashboardDebugTest::test_debug_ability_check":0.044,"Tests\\Feature\\DashboardDebugTest::test_debug":0.045,"Tests\\Feature\\ProductPriceTest::test_batch_price_updates_cost_and_notifies_all_stores":0.089,"Tests\\Feature\\ProductPriceTest::test_level_percent_update_notifies_level_stores":0.09,"Tests\\Feature\\ProductPriceTest::test_level_update_without_percent_change_sends_no_notice":0.048,"Tests\\Feature\\ProductPriceTest::test_level_percent_validation":0.008,"Tests\\Feature\\ProductCostPriceTest::test_calc_level_price":0.001,"Tests\\Feature\\ProductCostPriceTest::test_calc_level_price_edge_cases":0.001,"Tests\\Feature\\ProductCostPriceTest::test_admin_list_contains_cost_price_and_level_prices":0.01,"Tests\\Feature\\ProductCostPriceTest::test_create_product_with_cost_price":0.007,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_cost_row_update":0.051,"Tests\\Feature\\ProductCostPriceTest::test_price_matrix_includes_cost_and_level_price_columns":0.007,"Tests\\Feature\\ProductCostPriceTest::test_mini_order_uses_level_price":0.048,"Tests\\Feature\\ProductCostPriceTest::test_mini_cart_uses_level_price":0.048,"Tests\\Feature\\CartTest::test_store_level_missing_rejected":0.006,"Tests\\Feature\\StoreOrderTest::test_store_level_missing_rejected":0.047,"Tests\\Feature\\PurchaseEditTest::test_update_row_skips_catalog_sync_when_product_deleted":0.108,"Tests\\Feature\\PurchaseEditTest::test_store_item_add_creates_item_and_recalculates":0.106,"Tests\\Feature\\PurchaseEditTest::test_store_item_update_merges_multi_order_rows":0.06,"Tests\\Feature\\PurchaseEditTest::test_store_item_remove_deletes_and_recalculates":0.1,"Tests\\Feature\\StoreOrderItemTest::test_update_store_item_recalculates_totals":0.06,"Tests\\Feature\\StoreOrderItemTest::test_store_item_edits_rejected_when_purchase_completed":0.062,"Tests\\Feature\\StoreOrderItemTest::test_update_store_item_validates_negative_values":0.058,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_uses_level_percent_price":0.059,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_rejected_when_product_deleted":0.06,"Tests\\Feature\\ExportTest::test_export_lists_all_catalog_products_with_totals_row":0.101,"Tests\\Feature\\ExportTest::test_export_supplier_filter":0.101,"Tests\\Feature\\ExportTest::test_export_stores_multi_sheet":0.102,"Tests\\Feature\\ExportTest::test_export_stores_single_store":0.101,"Tests\\Feature\\ExportTest::test_export_stores_without_items_rejected":0.144,"Tests\\Feature\\ExportTest::test_export_suppliers_multi_sheet":0.103,"Tests\\Feature\\ExportTest::test_export_suppliers_single":0.103,"Tests\\Feature\\ExportTest::test_export_suppliers_without_items_rejected":0.102,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_change_reprices_items_by_store_level":0.102,"Tests\\Feature\\PurchaseEditTest::test_update_row_without_cost_change_keeps_item_price":0.105,"Tests\\Feature\\CartTest::test_update_other_stores_item_rejected":0.09,"Tests\\Feature\\CartTest::test_delete_other_stores_item_rejected":0.089,"Tests\\Feature\\CartTest::test_cart_isolated_between_stores":0.09,"Tests\\Feature\\MiniAuthTest::test_login_issues_token_for_valid_credentials":0.127,"Tests\\Feature\\MiniAuthTest::test_login_rejects_wrong_password":0.123,"Tests\\Feature\\MiniAuthTest::test_login_rejects_unknown_username":0.002,"Tests\\Feature\\MiniAuthTest::test_disabled_store_cannot_login":0.123,"Tests\\Feature\\MiniAuthTest::test_login_validates_required_params":0.002,"Tests\\Feature\\MiniAuthTest::test_login_token_accesses_protected_routes":0.126,"Tests\\Feature\\MiniAuthTest::test_set_password_succeeds":0.207,"Tests\\Feature\\MiniAuthTest::test_set_password_rejects_wrong_old_password":0.124,"Tests\\Feature\\MiniAuthTest::test_set_password_validates_confirmation":0.045,"Tests\\Feature\\BillExportTest::test_mini_export_scoped_to_own_store":0.093,"Tests\\Feature\\MiniNoticeTest::test_other_stores_notice_not_found":0.086,"Tests\\Feature\\MiniProductTest::test_product_detail_store_sees_level_price":0.047,"Tests\\Feature\\MiniProductTest::test_product_list_store_sees_level_price":0.045,"Tests\\Feature\\MiniStoreTest::test_info_returns_current_store":0.045,"Tests\\Feature\\MiniStoreTest::test_disabled_store_rejected":0.047,"Tests\\Feature\\ProductImportExportTest::test_export_downloads_all_products":0.008,"Tests\\Feature\\ProductImportExportTest::test_export_filters_by_category":0.008,"Tests\\Feature\\ProductImportExportTest::test_export_template_mode":0.005,"Tests\\Feature\\ProductImportExportTest::test_export_requires_permission":0.007,"Tests\\Feature\\ProductImportExportTest::test_import_creates_products_and_auto_supplier":0.043,"Tests\\Feature\\ProductImportExportTest::test_import_matches_existing_supplier":0.019,"Tests\\Feature\\ProductImportExportTest::test_import_errors_abort_all_rows":0.017,"Tests\\Feature\\ProductImportExportTest::test_import_category_path_resolution":0.031,"Tests\\Feature\\ProductImportExportTest::test_import_rejects_invalid_header":0.014,"Tests\\Feature\\ProductImportExportTest::test_import_requires_permission":0.01,"Tests\\Feature\\ProductImportExportTest::test_list_filters_by_market":0.008,"Tests\\Feature\\MiniReportTest::test_report_aggregates_total_and_item_percent":0.047,"Tests\\Feature\\MiniReportTest::test_report_accumulates_same_product_across_orders":0.048,"Tests\\Feature\\MiniReportTest::test_report_filters_by_custom_date_range":0.047,"Tests\\Feature\\MiniReportTest::test_report_excludes_cancelled_and_deleted_orders":0.047,"Tests\\Feature\\MiniReportTest::test_report_preset_month_and_last_month":0.049,"Tests\\Feature\\MiniReportTest::test_report_preset_week_and_last_week":0.051,"Tests\\Feature\\MiniReportTest::test_report_defaults_to_current_month":0.047,"Tests\\Feature\\MiniReportTest::test_report_data_isolated_between_stores":0.086,"Tests\\Feature\\MiniReportTest::test_report_empty_period_returns_zero":0.046,"Tests\\Feature\\MiniReportTest::test_report_validates_params":0.049,"Tests\\Feature\\ProductBatchDeleteTest::test_batch_delete_soft_deletes_selected_products":0.009,"Tests\\Feature\\ProductBatchDeleteTest::test_batch_delete_requires_non_empty_ids":0.006,"Tests\\Feature\\ProductBatchDeleteTest::test_batch_delete_forbidden_without_permission":0.007,"Tests\\Feature\\CartTest::test_place_order_clears_ordered_items_from_cart":0.072,"Tests\\Feature\\StoreOrderItemTest::test_admin_order_list_filters_by_order_date_range":0.064,"Tests\\Feature\\StoreOrderItemTest::test_admin_order_list_search_by_purchase_no":0.064,"Tests\\Feature\\ExportTest::test_export_suppliers_split_by_market":0.058,"Tests\\Feature\\BillPaymentTest::test_generate_bill_saves_after_sale_and_remark":0.119,"Tests\\Feature\\ProductCostPriceTest::test_product_price_unit_default_and_editable":0.013,"Tests\\Feature\\StoreOrderTest::test_place_order_blocked_by_overdue_unpaid_bill":0.057,"Tests\\Feature\\StoreOrderTest::test_place_order_allowed_within_payment_cycle":0.056,"Tests\\Feature\\CartTest::test_cart_summary_endpoint":0.053,"Tests\\Feature\\CartTest::test_cart_summary_requires_login":0.002,"Tests\\Feature\\MiniProductTest::test_product_list_appends_cart_quantity_and_summary":0.053,"Tests\\Feature\\MiniProductTest::test_product_list_guest_sees_zero_cart_fields":0.045,"Tests\\Feature\\MiniProductTest::test_product_detail_appends_cart_quantity":0.049,"Tests\\Feature\\MiniProductTest::test_home_appends_cart_summary":0.065,"Tests\\Feature\\MiniOnlinePaymentTest::test_sign_matches_document_example":0.002,"Tests\\Feature\\MiniOnlinePaymentTest::test_create_online_payment_success":0.068,"Tests\\Feature\\MiniOnlinePaymentTest::test_create_online_payment_validation":0.097,"Tests\\Feature\\MiniOnlinePaymentTest::test_create_fails_when_code2session_fails":0.047,"Tests\\Feature\\MiniOnlinePaymentTest::test_create_gateway_failure_releases_bills":0.052,"Tests\\Feature\\MiniOnlinePaymentTest::test_notify_settles_payment":0.053,"Tests\\Feature\\MiniOnlinePaymentTest::test_notify_rejects_invalid_messages":0.058,"Tests\\Feature\\MiniOnlinePaymentTest::test_query_syncs_gateway_status":0.061,"Tests\\Feature\\MiniOnlinePaymentTest::test_query_rejects_other_store_payment":0.088,"Tests\\Feature\\MiniOnlinePaymentTest::test_offline_payment_flow_unaffected":0.049,"Tests\\Feature\\BillPaymentTest::test_generate_bill_positive_after_sale_added_to_total":0.114,"Tests\\Feature\\BillPaymentTest::test_generate_bill_rejects_non_numeric_after_sale":0.048,"Tests\\Feature\\ClientSpecialTest::test_batch_add_creates_specials":0.01,"Tests\\Feature\\ClientSpecialTest::test_batch_add_skips_existing_products":0.007,"Tests\\Feature\\ClientSpecialTest::test_batch_add_requires_non_empty_product_ids":0.006,"Tests\\Feature\\ClientSpecialTest::test_batch_add_forbidden_without_permission":0.007,"Tests\\Feature\\ClientSpecialTest::test_query_filters_by_product_name_keyword":0.007,"Tests\\Feature\\ClientSpecialTest::test_update_changes_sort_and_status":0.007,"Tests\\Feature\\ClientSpecialTest::test_delete_and_batch_delete":0.008,"Tests\\Feature\\ClientSpecialTest::test_batch_delete_requires_non_empty_ids":0.007,"Tests\\Feature\\MiniSpecialTest::test_guest_sees_specials_with_null_price":0.045,"Tests\\Feature\\MiniSpecialTest::test_store_sees_level_price":0.048,"Tests\\Feature\\MiniSpecialTest::test_disabled_special_and_off_shelf_product_excluded":0.045,"Tests\\Feature\\MiniSpecialTest::test_specials_sorted_by_sort_asc":0.087,"Tests\\Feature\\MiniSpecialTest::test_cart_quantity_attached_for_store":0.046,"Tests\\Feature\\MiniOnlinePaymentTest::test_aes_encryption_matches_demo_golden":0.002,"Tests\\Feature\\MiniOnlinePaymentTest::test_notify_envelope_round_trip":0.005,"Tests\\Feature\\MiniOnlinePaymentTest::test_swapped_key_config_fails_with_clear_message":0.004,"Tests\\Feature\\MiniWechatPaymentTest::test_create_wechat_payment_success":0.068,"Tests\\Feature\\MiniWechatPaymentTest::test_create_wechat_payment_gateway_failure_releases_bills":0.053,"Tests\\Feature\\MiniWechatPaymentTest::test_wechat_notify_settles_payment":0.056,"Tests\\Feature\\MiniWechatPaymentTest::test_wechat_notify_rejects_invalid_messages":0.053,"Tests\\Feature\\MiniWechatPaymentTest::test_wechat_notify_with_platform_cert_validates_signature":0.052,"Tests\\Feature\\MiniWechatPaymentTest::test_wechat_query_syncs_status":0.057,"Tests\\Feature\\MiniWechatPaymentTest::test_wangpu_channel_remains_default":0.049}} \ No newline at end of file +{"version":2,"defects":{"Tests\\Feature\\ProductPriceTest::test_product_list_returns_price_for_store_level":8,"Tests\\Feature\\ProductPriceTest::test_store_without_level_is_rejected":8,"Tests\\Feature\\ProductPriceTest::test_batch_price_updates_and_notifies_affected_stores":7,"Tests\\Feature\\ProductPriceTest::test_price_matrix_structure":8,"Tests\\Feature\\StoreOrderTest::test_place_order_snapshots_level_price_and_recalculates":8,"Tests\\Feature\\StoreOrderTest::test_client_supplied_amount_is_ignored":8,"Tests\\Feature\\StoreOrderTest::test_product_without_level_price_rejected":8,"Tests\\Feature\\StoreOrderTest::test_cancel_only_pending_orders":8,"Tests\\Feature\\StoreOrderTest::test_summarized_order_cannot_be_cancelled":8,"Tests\\Feature\\StoreOrderTest::test_order_data_isolated_between_stores":8,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_orders_by_product":7,"Tests\\Feature\\PurchaseGenerateTest::test_generate_writes_back_order_status":7,"Tests\\Feature\\PurchaseGenerateTest::test_generate_without_pending_orders_fails":8,"Tests\\Feature\\PurchaseGenerateTest::test_generate_is_idempotent":7,"Tests\\Feature\\AllocationTest::test_allocation_conserves_amount_with_tail_correction":7,"Tests\\Feature\\AllocationTest::test_allocation_follows_order_ratio":7,"Tests\\Feature\\AllocationTest::test_allocation_is_idempotent":7,"Tests\\Feature\\AllocationTest::test_allocation_rejected_without_actual_amount":8,"Tests\\Feature\\MiniAuthTest::test_login_creates_user_and_issues_token":7,"Tests\\Feature\\MiniAuthTest::test_phone_binding_matches_store":8,"Tests\\Feature\\MiniAuthTest::test_phone_no_match_stays_pending":8,"Tests\\Feature\\ExportTest::test_export_xlsx_with_encoded_chinese_filename":7,"Tests\\Feature\\CartTest::test_list_with_prices_amounts_and_totals":7,"Tests\\Feature\\CartTest::test_list_marks_off_shelf_item_unbuyable":7,"Tests\\Feature\\DebugCartListTest::test_dump_cart_list_response":5,"Tests\\Feature\\ProductCostPriceTest::test_create_product_with_cost_and_percent_pricing":7,"Tests\\Feature\\ProductCostPriceTest::test_create_percent_row_without_percent_fails":7,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_cost_only_notifies_percent_level_stores":7,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_empty_row_rejected":7,"Tests\\Feature\\MiniAuthTest::test_disabled_user_cannot_login":8,"Tests\\Feature\\MiniAuthTest::test_mini_token_cannot_access_admin_api":8,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_percent_row_update":7,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_mixed_row_updates_cost_and_level":7,"Tests\\Feature\\ReconciliationTest::test_build_creates_reconciliation_items":8,"Tests\\Feature\\ReconciliationTest::test_build_filters_by_supplier":8,"Tests\\Feature\\ReconciliationTest::test_update_item_recalculates_diff_and_header":8,"Tests\\Feature\\ReconciliationTest::test_toggle_reconciled_flag":8,"Tests\\Feature\\ReconciliationTest::test_settle_creates_settlements_per_store":8,"Tests\\Feature\\ProductCostPriceTest::test_mini_list_returns_actual_price_without_cost_price":8,"Tests\\Feature\\ProductCostPriceTest::test_mini_order_uses_actual_price_for_percent_row":8,"Tests\\Feature\\ProductCostPriceTest::test_mini_cart_uses_actual_price_for_percent_row":8,"Tests\\Feature\\StoreOrderTest::test_container_update_recalculates_amounts":8,"Tests\\Feature\\StoreOrderTest::test_container_update_allowed_in_editable_statuses":8,"Tests\\Feature\\StoreOrderTest::test_container_update_rejected_in_other_statuses":8,"Tests\\Feature\\StoreOrderTest::test_container_update_heals_legacy_product_amount":8,"Tests\\Feature\\StoreOrderTest::test_container_update_validates_negative_numbers":8,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_rejected_when_product_deleted":7,"Tests\\Feature\\StoreOrderItemTest::test_order_list_search_by_product_name":8,"Tests\\Feature\\PurchaseEditTest::test_detail_returns_store_matrix":7,"Tests\\Feature\\PurchaseEditTest::test_update_cell_syncs_order_item_and_totals":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_syncs_all_order_items":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_weight_distributed_by_quantity":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_product_attributes":7,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_order_items_into_header":7,"Tests\\Feature\\ExportTest::test_export_category_filters_to_vegetables":7,"Tests\\Feature\\ExportTest::test_export_pdf":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_does_not_touch_manual_weight":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_to_product_catalog":7,"Tests\\Feature\\PurchaseEditTest::test_update_cell_weight_cascades_totals":7,"Tests\\Feature\\PurchaseEditTest::test_cell_sync_refreshes_snapshot_and_cascades":7,"Tests\\Feature\\PurchaseEditTest::test_edits_rejected_when_purchase_completed":7,"Tests\\Feature\\StoreOrderItemTest::test_update_item_recalculates_order_totals":7,"Tests\\Feature\\StoreOrderItemTest::test_update_item_validates_negative_price":7,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_updates_snapshot_from_product":7,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_recalculates_percent_price_with_latest_cost":7,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_returns_items_with_order_info":8,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_leaf_category_ok":7,"Tests\\Feature\\BillExportTest::test_export_filters_by_root_category":8,"Tests\\Feature\\BillExportTest::test_export_requires_export_permission":8,"Tests\\Feature\\DebugPermissionTest::test_debug_permission":8,"Tests\\Feature\\BillPaymentTest::test_order_status_progresses_via_business_chain":7,"Tests\\Feature\\BillPaymentTest::test_payment_audit_reject_does_not_accumulate":7,"Tests\\Feature\\BillPaymentTest::test_payment_detail_returns_voucher_urls":8,"Tests\\Feature\\ContainerReturnTest::test_press_containers_adds_amount_and_writes_record":7,"Tests\\Feature\\ContainerReturnTest::test_return_containers_deducts_amount":7,"Tests\\Feature\\ContainerReturnTest::test_mixed_sign_containers":7,"Tests\\Feature\\ContainerReturnTest::test_zero_containers_writes_no_record":7,"Tests\\Feature\\StoreOrderTest::test_order_list_outputs_status_name_and_item_preview":7,"Tests\\Feature\\DashboardTest::test_requires_dashboard_analysis_ability":7,"Tests\\Feature\\DashboardTest::test_recon_summary_and_receivable":8,"Tests\\Feature\\DashboardDebugTest::test_debug":8,"Tests\\Feature\\StoreOrderItemTest::test_place_order_snapshots_full_product_info":8,"Tests\\Feature\\StoreOrderItemTest::test_mini_detail_hides_cost_price":8,"Tests\\Feature\\StoreOrderItemTest::test_admin_detail_shows_cost_price_and_supplier":8,"Tests\\Feature\\StoreOrderItemTest::test_update_item_rejected_when_completed_or_cancelled":8,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_uses_level_percent_price":8,"Tests\\Feature\\ExportTest::test_export_suppliers_multi_sheet":7,"Tests\\Feature\\PurchaseEditTest::test_update_row_skips_catalog_sync_when_product_deleted":7,"Tests\\Feature\\ProductImportExportTest::test_export_filters_by_category":8,"Tests\\Feature\\ProductImportExportTest::test_import_creates_products_and_auto_supplier":7,"Tests\\Feature\\ProductImportExportTest::test_import_matches_existing_supplier":7,"Tests\\Feature\\ProductImportExportTest::test_import_errors_abort_all_rows":7,"Tests\\Feature\\ProductImportExportTest::test_import_category_path_resolution":7,"Tests\\Feature\\MiniReportTest::test_report_accumulates_same_product_across_orders":7,"Tests\\Feature\\ExportTest::test_export_suppliers_split_by_market":7,"Tests\\Feature\\MiniOnlinePaymentTest::test_query_syncs_gateway_status":7,"Tests\\Feature\\MiniSpecialTest::test_cart_quantity_attached_for_store":8,"Tests\\Feature\\MiniWechatPaymentTest::test_create_wechat_payment_success":7,"Tests\\Feature\\ExportTest::test_export_lists_all_catalog_products_with_totals_row":7},"times":{"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.018,"Tests\\Feature\\ProductPriceTest::test_product_list_returns_price_for_store_level":0.089,"Tests\\Feature\\ProductPriceTest::test_store_without_level_is_rejected":0.007,"Tests\\Feature\\ProductPriceTest::test_batch_price_updates_and_notifies_affected_stores":0.01,"Tests\\Feature\\ProductPriceTest::test_price_matrix_structure":0.006,"Tests\\Feature\\StoreOrderTest::test_place_order_snapshots_level_price_and_recalculates":0.047,"Tests\\Feature\\StoreOrderTest::test_client_supplied_amount_is_ignored":0.046,"Tests\\Feature\\StoreOrderTest::test_product_without_level_price_rejected":0.007,"Tests\\Feature\\StoreOrderTest::test_cancel_only_pending_orders":0.052,"Tests\\Feature\\StoreOrderTest::test_summarized_order_cannot_be_cancelled":0.053,"Tests\\Feature\\StoreOrderTest::test_order_data_isolated_between_stores":0.093,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_orders_by_product":0.028,"Tests\\Feature\\PurchaseGenerateTest::test_generate_writes_back_order_status":0.102,"Tests\\Feature\\PurchaseGenerateTest::test_generate_without_pending_orders_fails":0.006,"Tests\\Feature\\PurchaseGenerateTest::test_generate_is_idempotent":0.101,"Tests\\Feature\\AllocationTest::test_allocation_conserves_amount_with_tail_correction":0.076,"Tests\\Feature\\AllocationTest::test_allocation_follows_order_ratio":0.022,"Tests\\Feature\\AllocationTest::test_allocation_is_idempotent":0.028,"Tests\\Feature\\AllocationTest::test_allocation_rejected_without_actual_amount":0.021,"Tests\\Feature\\DebugGenerateTest::test_debug_generate":0.047,"Tests\\Feature\\ReconciliationTest::test_build_creates_reconciliation_items":0.019,"Tests\\Feature\\ReconciliationTest::test_build_filters_by_supplier":0.022,"Tests\\Feature\\ReconciliationTest::test_update_item_recalculates_diff_and_header":0.019,"Tests\\Feature\\ReconciliationTest::test_toggle_reconciled_flag":0.02,"Tests\\Feature\\ReconciliationTest::test_settle_creates_settlements_per_store":0.036,"Tests\\Feature\\StatementTest::test_generate_snapshots_payment_cycle":0.011,"Tests\\Feature\\StatementTest::test_statement_isolated_between_stores":0.013,"Tests\\Feature\\StatementTest::test_generate_excludes_cancelled_and_used_items":0.016,"Tests\\Feature\\MiniAuthTest::test_login_creates_user_and_issues_token":0.056,"Tests\\Feature\\MiniAuthTest::test_disabled_user_cannot_login":0.003,"Tests\\Feature\\MiniAuthTest::test_phone_binding_matches_store":0.005,"Tests\\Feature\\MiniAuthTest::test_phone_no_match_stays_pending":0.001,"Tests\\Feature\\MiniAuthTest::test_sys_token_cannot_access_mini":0.006,"Tests\\Feature\\MiniAuthTest::test_mini_token_cannot_access_admin_api":0.045,"Tests\\Feature\\ExportTest::test_export_xlsx_with_encoded_chinese_filename":0.112,"Tests\\Feature\\ExportTest::test_export_category_filters_to_vegetables":0.017,"Tests\\Feature\\ExportTest::test_export_pdf":0.015,"Tests\\Feature\\ExportTest::test_export_invalid_format_rejected":0.016,"Tests\\Feature\\ExportTest::test_export_requires_export_permission":0.056,"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.001,"Tests\\Feature\\MiniAuthTest::test_login_fails_when_wechat_rejects_code":0.003,"Tests\\Feature\\CartTest::test_add_to_cart_succeeds":0.047,"Tests\\Feature\\CartTest::test_duplicate_add_merges_quantity":0.048,"Tests\\Feature\\CartTest::test_off_shelf_product_rejected":0.046,"Tests\\Feature\\CartTest::test_soft_deleted_product_rejected":0.008,"Tests\\Feature\\CartTest::test_product_without_level_price_rejected":0.006,"Tests\\Feature\\CartTest::test_unbound_user_rejected":0.006,"Tests\\Feature\\CartTest::test_store_without_level_rejected":0.086,"Tests\\Feature\\CartTest::test_list_with_prices_amounts_and_totals":0.049,"Tests\\Feature\\CartTest::test_list_marks_off_shelf_item_unbuyable":0.052,"Tests\\Feature\\CartTest::test_empty_cart_returns_empty_items":0.057,"Tests\\Feature\\CartTest::test_update_quantity":0.048,"Tests\\Feature\\CartTest::test_update_other_users_item_rejected":0.009,"Tests\\Feature\\CartTest::test_update_missing_item_rejected":0.047,"Tests\\Feature\\CartTest::test_invalid_quantity_rejected":0.046,"Tests\\Feature\\CartTest::test_delete_item":0.047,"Tests\\Feature\\CartTest::test_delete_other_users_item_rejected":0.009,"Tests\\Feature\\CartTest::test_clear_only_own_cart":0.097,"Tests\\Feature\\CartTest::test_unauthenticated_returns_401":0.002,"Tests\\Feature\\CartTest::test_cart_isolated_between_users":0.011,"Tests\\Feature\\DebugCartListTest::test_dump_cart_list_response":0.057,"Tests\\Feature\\ProductCostPriceTest::test_calc_actual_price_fixed_and_percent":0.001,"Tests\\Feature\\ProductCostPriceTest::test_calc_actual_price_edge_cases":0.001,"Tests\\Feature\\ProductCostPriceTest::test_admin_list_contains_cost_price_and_actual_price":0.009,"Tests\\Feature\\ProductCostPriceTest::test_mini_list_returns_actual_price_without_cost_price":0.045,"Tests\\Feature\\ProductCostPriceTest::test_create_product_with_cost_and_percent_pricing":0.008,"Tests\\Feature\\ProductCostPriceTest::test_create_percent_row_without_percent_fails":0.007,"Tests\\Feature\\ProductCostPriceTest::test_update_switches_fixed_to_percent":0.01,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_cost_only_notifies_percent_level_stores":0.01,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_percent_row_update":0.009,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_mixed_row_updates_cost_and_level":0.008,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_empty_row_rejected":0.009,"Tests\\Feature\\ProductCostPriceTest::test_price_matrix_includes_cost_and_percent_columns":0.007,"Tests\\Feature\\ProductCostPriceTest::test_mini_order_uses_actual_price_for_percent_row":0.007,"Tests\\Feature\\ProductCostPriceTest::test_mini_cart_uses_actual_price_for_percent_row":0.01,"Tests\\Feature\\PurchaseGenerateTest::test_generate_uses_min_actual_price_across_types":0.014,"Tests\\Feature\\ProductPriceTest::test_store_without_level_sees_products_without_price":0.046,"Tests\\Feature\\ProductPriceTest::test_unbound_user_can_browse_products_without_price_but_cannot_cart":0.009,"Tests\\Feature\\MiniAuthTest::test_login_issues_token_for_registered_user":0.01,"Tests\\Feature\\MiniAuthTest::test_login_rejects_unregistered_openid":0.002,"Tests\\Feature\\MiniAuthTest::test_register_binds_store_and_issues_token":0.009,"Tests\\Feature\\MiniAuthTest::test_register_rejects_unknown_store":0.002,"Tests\\Feature\\MiniAuthTest::test_register_rejects_duplicate_openid":0.003,"Tests\\Feature\\MiniStoreTest::test_info_returns_bound_store":0.005,"Tests\\Feature\\MiniStoreTest::test_update_info":0.047,"Tests\\Feature\\MiniStoreTest::test_update_info_ignores_readonly_fields":0.047,"Tests\\Feature\\MiniStoreTest::test_requires_bound_store":0.007,"Tests\\Feature\\MiniStoreTest::test_update_info_validates_length":0.046,"Tests\\Feature\\StoreOrderTest::test_container_update_recalculates_amounts":0.012,"Tests\\Feature\\StoreOrderTest::test_container_update_allowed_in_editable_statuses":0.022,"Tests\\Feature\\StoreOrderTest::test_container_update_rejected_in_other_statuses":0.019,"Tests\\Feature\\StoreOrderTest::test_container_update_heals_legacy_product_amount":0.02,"Tests\\Feature\\StoreOrderTest::test_container_update_validates_negative_numbers":0.014,"Tests\\Feature\\PurchaseGenerateTest::test_generate_without_accepted_orders_fails":0.052,"Tests\\Feature\\PurchaseGenerateTest::test_generate_with_selected_order_ids":0.104,"Tests\\Feature\\StoreOrderItemTest::test_place_order_snapshots_full_product_info":0.049,"Tests\\Feature\\StoreOrderItemTest::test_mini_detail_hides_cost_price":0.05,"Tests\\Feature\\StoreOrderItemTest::test_admin_detail_shows_cost_price_and_supplier":0.054,"Tests\\Feature\\StoreOrderItemTest::test_update_item_recalculates_order_totals":0.011,"Tests\\Feature\\StoreOrderItemTest::test_update_item_rejected_when_completed_or_cancelled":0.011,"Tests\\Feature\\StoreOrderItemTest::test_update_item_validates_negative_price":0.012,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_updates_snapshot_from_product":0.013,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_recalculates_percent_price_with_latest_cost":0.01,"Tests\\Feature\\StoreOrderItemTest::test_sync_item_rejected_when_product_deleted":0.01,"Tests\\Feature\\StoreOrderItemTest::test_order_list_search_by_product_name":0.058,"Tests\\Feature\\StoreOrderTest::test_soft_delete_only_cancelled_orders":0.063,"Tests\\Feature\\StoreOrderTest::test_soft_delete_rejected_for_non_cancelled_orders":0.246,"Tests\\Feature\\StoreOrderTest::test_soft_delete_twice_rejected":0.053,"Tests\\Feature\\PurchaseEditTest::test_detail_returns_store_matrix":0.107,"Tests\\Feature\\PurchaseEditTest::test_update_cell_syncs_order_item_and_totals":0.102,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_syncs_all_order_items":0.104,"Tests\\Feature\\PurchaseEditTest::test_update_row_weight_distributed_by_quantity":0.032,"Tests\\Feature\\PurchaseEditTest::test_update_row_requires_at_least_one_field":0.099,"Tests\\Feature\\PurchaseEditTest::test_update_cell_rejects_negative_quantity":0.101,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_order_items_into_header":0.1,"Tests\\Feature\\ReconciliationTest::test_build_excludes_unfinished_orders":0.016,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_product_attributes":0.108,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_to_product_catalog":0.019,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_returns_items_with_order_info":0.103,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_rejects_missing_params":0.101,"Tests\\Feature\\PurchaseEditTest::test_update_cell_weight_cascades_totals":0.101,"Tests\\Feature\\PurchaseEditTest::test_cell_sync_refreshes_snapshot_and_cascades":0.012,"Tests\\Feature\\PurchaseEditTest::test_edits_rejected_when_purchase_completed":0.12,"Tests\\Feature\\PurchaseEditTest::test_update_row_does_not_touch_manual_weight":0.107,"Tests\\Feature\\PurchaseEditTest::test_store_summary_returns_aggregated_items":0.102,"Tests\\Feature\\PurchaseEditTest::test_store_summary_aggregates_multiple_orders_with_weighted_price":0.059,"Tests\\Feature\\PurchaseEditTest::test_store_summary_rejects_missing_or_invalid_params":0.101,"Tests\\Feature\\ExportTest::test_export_invalid_type_rejected":0.016,"Tests\\Feature\\ExportTest::test_export_missing_purchase_rejected":0.008,"Tests\\Feature\\PurchaseEditTest::test_detail_returns_container_summary":0.022,"Tests\\Feature\\PurchaseEditTest::test_update_container_syncs_order_amounts":0.018,"Tests\\Feature\\PurchaseEditTest::test_update_container_rejected_when_purchase_completed":0.018,"Tests\\Feature\\PurchaseEditTest::test_update_container_rejects_incomplete_or_foreign_orders":0.026,"Tests\\Feature\\PurchaseEditTest::test_update_container_validates_negative_and_duplicate_orders":0.018,"Tests\\Feature\\ProductCategoryTest::test_create_child_category_under_top_level":0.006,"Tests\\Feature\\ProductCategoryTest::test_create_category_under_second_level_rejected":0.006,"Tests\\Feature\\ProductCategoryTest::test_update_second_level_move_to_another_top":0.006,"Tests\\Feature\\ProductCategoryTest::test_update_parent_with_children_cannot_move_under_category":0.007,"Tests\\Feature\\ProductCategoryTest::test_update_with_missing_parent_rejected":0.007,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_parent_category_rejected":0.008,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_leaf_category_ok":0.007,"Tests\\Feature\\ProductCategoryTest::test_mini_categories_returns_all_enabled_categories":0.045,"Tests\\Feature\\MiniBillTest::test_bill_list_derives_pay_state_and_settlement_date":0.047,"Tests\\Feature\\MiniBillTest::test_bill_list_summary_aggregates_unpaid":0.047,"Tests\\Feature\\MiniBillTest::test_bill_list_payable_filter":0.047,"Tests\\Feature\\MiniBillTest::test_bill_list_filters_by_bill_date_range":0.051,"Tests\\Feature\\MiniBillTest::test_bill_data_isolated_between_stores":0.088,"Tests\\Feature\\MiniBillTest::test_bill_detail_outputs_bill_items_and_orders":0.051,"Tests\\Feature\\StoreOrderTest::test_order_list_outputs_status_name_and_item_preview":0.054,"Tests\\Feature\\StoreOrderTest::test_order_list_filters_by_order_date_range":0.058,"Tests\\Feature\\StoreOrderTest::test_order_list_rejects_invalid_filters":0.049,"Tests\\Feature\\BillExportTest::test_export_merges_items_across_bills":0.112,"Tests\\Feature\\BillExportTest::test_export_filters_by_root_category":0.05,"Tests\\Feature\\BillExportTest::test_export_empty_category_rejected":0.089,"Tests\\Feature\\BillExportTest::test_export_requires_export_permission":0.05,"Tests\\Feature\\BillExportTest::test_export_invalid_ids_rejected":0.009,"Tests\\Feature\\DebugPermissionTest::test_debug_permission":0.098,"Tests\\Feature\\BillExportTest::test_mini_export_scoped_to_bound_store":0.014,"Tests\\Feature\\BillExportTest::test_mini_export_requires_store_binding":0.005,"Tests\\Feature\\MiniNoticeTest::test_notice_list_includes_personal_and_broadcast":0.047,"Tests\\Feature\\MiniNoticeTest::test_broadcast_read_creates_personal_copy":0.048,"Tests\\Feature\\MiniNoticeTest::test_personal_notice_read_marks_directly":0.046,"Tests\\Feature\\MiniNoticeTest::test_other_users_notice_not_found":0.007,"Tests\\Feature\\StoreOrderTest::test_manual_status_flow_only_accept_and_cancel":0.1,"Tests\\Feature\\StoreOrderTest::test_manual_status_flow_rejects_delivery_and_completion":0.148,"Tests\\Feature\\StoreOrderTest::test_batch_status_only_accept_and_cancel":0.101,"Tests\\Feature\\BillPaymentTest::test_order_status_progresses_via_business_chain":0.066,"Tests\\Feature\\BillPaymentTest::test_manual_pay_accumulates_store_total_purchase_amount":0.069,"Tests\\Feature\\BillPaymentTest::test_payment_audit_pass_accumulates_store_total_purchase_amount":0.051,"Tests\\Feature\\BillPaymentTest::test_payment_audit_reject_does_not_accumulate":0.048,"Tests\\Feature\\MiniProductTest::test_product_detail_guest_sees_null_price":0.045,"Tests\\Feature\\MiniProductTest::test_product_detail_store_user_sees_level_price":0.006,"Tests\\Feature\\MiniProductTest::test_product_detail_percent_price_calculated_from_cost":0.046,"Tests\\Feature\\MiniProductTest::test_product_detail_off_shelf_or_missing_rejected":0.046,"Tests\\Feature\\MiniProductTest::test_product_list_store_user_sees_level_price":0.005,"Tests\\Feature\\MiniProductTest::test_product_list_guest_sees_null_price":0.044,"Tests\\Feature\\BillPaymentTest::test_admin_order_list_and_detail_show_bill_info":0.069,"Tests\\Feature\\BillPaymentTest::test_payment_detail_returns_voucher_urls":0.052,"Tests\\Feature\\StoreOrderTest::test_order_list_preview_includes_image_spec_and_unit":0.051,"Tests\\Feature\\ContainerReturnTest::test_press_containers_adds_amount_and_writes_record":0.062,"Tests\\Feature\\ContainerReturnTest::test_return_containers_deducts_amount":0.059,"Tests\\Feature\\ContainerReturnTest::test_mixed_sign_containers":0.059,"Tests\\Feature\\ContainerReturnTest::test_zero_containers_writes_no_record":0.06,"Tests\\Feature\\ContainerReturnTest::test_non_integer_containers_rejected":0.048,"Tests\\Feature\\ContainerReturnTest::test_manual_create_and_delete_routes_removed":0.023,"Tests\\Feature\\ContainerReturnTest::test_export_matrix_merges_same_day_and_zero_fills":0.089,"Tests\\Feature\\ContainerReturnTest::test_export_filters_by_selected_stores":0.128,"Tests\\Feature\\ContainerReturnTest::test_export_invalid_params_rejected":0.009,"Tests\\Feature\\ContainerReturnTest::test_export_empty_range_rejected":0.006,"Tests\\Feature\\ContainerReturnTest::test_export_requires_export_permission":0.007,"Tests\\Feature\\DashboardTest::test_guest_cannot_access_dashboard":0.002,"Tests\\Feature\\DashboardTest::test_requires_dashboard_analysis_ability":0.007,"Tests\\Feature\\DashboardTest::test_empty_database_returns_zero_structure":0.01,"Tests\\Feature\\DashboardTest::test_overview_excludes_cancelled_orders":0.05,"Tests\\Feature\\DashboardTest::test_week_growth_rate":0.054,"Tests\\Feature\\DashboardTest::test_trend_covers_30_days_with_zero_filling":0.051,"Tests\\Feature\\DashboardTest::test_category_sales_grouped_by_category":0.051,"Tests\\Feature\\DashboardTest::test_top_products_aggregated_across_orders":0.052,"Tests\\Feature\\DashboardTest::test_top_stores_ranked_by_amount":0.09,"Tests\\Feature\\DashboardTest::test_purchase_amount_prefers_actual_over_estimate":0.01,"Tests\\Feature\\DashboardTest::test_recon_summary_and_receivable":0.052,"Tests\\Feature\\DashboardTest::test_latest_orders_limited_and_ordered":0.052,"Tests\\Feature\\DashboardTest::test_archives_count_active_records_only":0.132,"Tests\\Feature\\DashboardDebugTest::test_debug_ability_check":0.044,"Tests\\Feature\\DashboardDebugTest::test_debug":0.045,"Tests\\Feature\\ProductPriceTest::test_batch_price_updates_cost_and_notifies_all_stores":0.09,"Tests\\Feature\\ProductPriceTest::test_level_percent_update_notifies_level_stores":0.103,"Tests\\Feature\\ProductPriceTest::test_level_update_without_percent_change_sends_no_notice":0.048,"Tests\\Feature\\ProductPriceTest::test_level_percent_validation":0.007,"Tests\\Feature\\ProductCostPriceTest::test_calc_level_price":0.001,"Tests\\Feature\\ProductCostPriceTest::test_calc_level_price_edge_cases":0.001,"Tests\\Feature\\ProductCostPriceTest::test_admin_list_contains_cost_price_and_level_prices":0.008,"Tests\\Feature\\ProductCostPriceTest::test_create_product_with_cost_price":0.007,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_cost_row_update":0.051,"Tests\\Feature\\ProductCostPriceTest::test_price_matrix_includes_cost_and_level_price_columns":0.007,"Tests\\Feature\\ProductCostPriceTest::test_mini_order_uses_level_price":0.048,"Tests\\Feature\\ProductCostPriceTest::test_mini_cart_uses_level_price":0.049,"Tests\\Feature\\CartTest::test_store_level_missing_rejected":0.006,"Tests\\Feature\\StoreOrderTest::test_store_level_missing_rejected":0.047,"Tests\\Feature\\PurchaseEditTest::test_update_row_skips_catalog_sync_when_product_deleted":0.104,"Tests\\Feature\\PurchaseEditTest::test_store_item_add_creates_item_and_recalculates":0.105,"Tests\\Feature\\PurchaseEditTest::test_store_item_update_merges_multi_order_rows":0.059,"Tests\\Feature\\PurchaseEditTest::test_store_item_remove_deletes_and_recalculates":0.105,"Tests\\Feature\\StoreOrderItemTest::test_update_store_item_recalculates_totals":0.059,"Tests\\Feature\\StoreOrderItemTest::test_store_item_edits_rejected_when_purchase_completed":0.061,"Tests\\Feature\\StoreOrderItemTest::test_update_store_item_validates_negative_values":0.056,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_uses_level_percent_price":0.057,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_rejected_when_product_deleted":0.058,"Tests\\Feature\\ExportTest::test_export_lists_all_catalog_products_with_totals_row":0.101,"Tests\\Feature\\ExportTest::test_export_supplier_filter":0.101,"Tests\\Feature\\ExportTest::test_export_stores_multi_sheet":0.103,"Tests\\Feature\\ExportTest::test_export_stores_single_store":0.101,"Tests\\Feature\\ExportTest::test_export_stores_without_items_rejected":0.143,"Tests\\Feature\\ExportTest::test_export_suppliers_multi_sheet":0.102,"Tests\\Feature\\ExportTest::test_export_suppliers_single":0.101,"Tests\\Feature\\ExportTest::test_export_suppliers_without_items_rejected":0.101,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_change_reprices_items_by_store_level":0.102,"Tests\\Feature\\PurchaseEditTest::test_update_row_without_cost_change_keeps_item_price":0.105,"Tests\\Feature\\CartTest::test_update_other_stores_item_rejected":0.09,"Tests\\Feature\\CartTest::test_delete_other_stores_item_rejected":0.089,"Tests\\Feature\\CartTest::test_cart_isolated_between_stores":0.089,"Tests\\Feature\\MiniAuthTest::test_login_issues_token_for_valid_credentials":0.126,"Tests\\Feature\\MiniAuthTest::test_login_rejects_wrong_password":0.124,"Tests\\Feature\\MiniAuthTest::test_login_rejects_unknown_username":0.002,"Tests\\Feature\\MiniAuthTest::test_disabled_store_cannot_login":0.123,"Tests\\Feature\\MiniAuthTest::test_login_validates_required_params":0.003,"Tests\\Feature\\MiniAuthTest::test_login_token_accesses_protected_routes":0.128,"Tests\\Feature\\MiniAuthTest::test_set_password_succeeds":0.21,"Tests\\Feature\\MiniAuthTest::test_set_password_rejects_wrong_old_password":0.126,"Tests\\Feature\\MiniAuthTest::test_set_password_validates_confirmation":0.046,"Tests\\Feature\\BillExportTest::test_mini_export_scoped_to_own_store":0.092,"Tests\\Feature\\MiniNoticeTest::test_other_stores_notice_not_found":0.086,"Tests\\Feature\\MiniProductTest::test_product_detail_store_sees_level_price":0.046,"Tests\\Feature\\MiniProductTest::test_product_list_store_sees_level_price":0.047,"Tests\\Feature\\MiniStoreTest::test_info_returns_current_store":0.045,"Tests\\Feature\\MiniStoreTest::test_disabled_store_rejected":0.048,"Tests\\Feature\\ProductImportExportTest::test_export_downloads_all_products":0.008,"Tests\\Feature\\ProductImportExportTest::test_export_filters_by_category":0.008,"Tests\\Feature\\ProductImportExportTest::test_export_template_mode":0.005,"Tests\\Feature\\ProductImportExportTest::test_export_requires_permission":0.007,"Tests\\Feature\\ProductImportExportTest::test_import_creates_products_and_auto_supplier":0.06,"Tests\\Feature\\ProductImportExportTest::test_import_matches_existing_supplier":0.016,"Tests\\Feature\\ProductImportExportTest::test_import_errors_abort_all_rows":0.015,"Tests\\Feature\\ProductImportExportTest::test_import_category_path_resolution":0.027,"Tests\\Feature\\ProductImportExportTest::test_import_rejects_invalid_header":0.016,"Tests\\Feature\\ProductImportExportTest::test_import_requires_permission":0.009,"Tests\\Feature\\ProductImportExportTest::test_list_filters_by_market":0.007,"Tests\\Feature\\MiniReportTest::test_report_aggregates_total_and_item_percent":0.047,"Tests\\Feature\\MiniReportTest::test_report_accumulates_same_product_across_orders":0.058,"Tests\\Feature\\MiniReportTest::test_report_filters_by_custom_date_range":0.047,"Tests\\Feature\\MiniReportTest::test_report_excludes_cancelled_and_deleted_orders":0.048,"Tests\\Feature\\MiniReportTest::test_report_preset_month_and_last_month":0.049,"Tests\\Feature\\MiniReportTest::test_report_preset_week_and_last_week":0.065,"Tests\\Feature\\MiniReportTest::test_report_defaults_to_current_month":0.048,"Tests\\Feature\\MiniReportTest::test_report_data_isolated_between_stores":0.088,"Tests\\Feature\\MiniReportTest::test_report_empty_period_returns_zero":0.046,"Tests\\Feature\\MiniReportTest::test_report_validates_params":0.052,"Tests\\Feature\\ProductBatchDeleteTest::test_batch_delete_soft_deletes_selected_products":0.021,"Tests\\Feature\\ProductBatchDeleteTest::test_batch_delete_requires_non_empty_ids":0.007,"Tests\\Feature\\ProductBatchDeleteTest::test_batch_delete_forbidden_without_permission":0.007,"Tests\\Feature\\CartTest::test_place_order_clears_ordered_items_from_cart":0.058,"Tests\\Feature\\StoreOrderItemTest::test_admin_order_list_filters_by_order_date_range":0.076,"Tests\\Feature\\StoreOrderItemTest::test_admin_order_list_search_by_purchase_no":0.063,"Tests\\Feature\\ExportTest::test_export_suppliers_split_by_market":0.057,"Tests\\Feature\\BillPaymentTest::test_generate_bill_saves_after_sale_and_remark":0.115,"Tests\\Feature\\ProductCostPriceTest::test_product_price_unit_default_and_editable":0.013,"Tests\\Feature\\StoreOrderTest::test_place_order_blocked_by_overdue_unpaid_bill":0.053,"Tests\\Feature\\StoreOrderTest::test_place_order_allowed_within_payment_cycle":0.054,"Tests\\Feature\\CartTest::test_cart_summary_endpoint":0.053,"Tests\\Feature\\CartTest::test_cart_summary_requires_login":0.002,"Tests\\Feature\\MiniProductTest::test_product_list_appends_cart_quantity_and_summary":0.052,"Tests\\Feature\\MiniProductTest::test_product_list_guest_sees_zero_cart_fields":0.046,"Tests\\Feature\\MiniProductTest::test_product_detail_appends_cart_quantity":0.049,"Tests\\Feature\\MiniProductTest::test_home_appends_cart_summary":0.05,"Tests\\Feature\\MiniOnlinePaymentTest::test_sign_matches_document_example":0.002,"Tests\\Feature\\MiniOnlinePaymentTest::test_create_online_payment_success":0.073,"Tests\\Feature\\MiniOnlinePaymentTest::test_create_online_payment_validation":0.098,"Tests\\Feature\\MiniOnlinePaymentTest::test_create_fails_when_code2session_fails":0.048,"Tests\\Feature\\MiniOnlinePaymentTest::test_create_gateway_failure_releases_bills":0.052,"Tests\\Feature\\MiniOnlinePaymentTest::test_notify_settles_payment":0.053,"Tests\\Feature\\MiniOnlinePaymentTest::test_notify_rejects_invalid_messages":0.058,"Tests\\Feature\\MiniOnlinePaymentTest::test_query_syncs_gateway_status":0.061,"Tests\\Feature\\MiniOnlinePaymentTest::test_query_rejects_other_store_payment":0.091,"Tests\\Feature\\MiniOnlinePaymentTest::test_offline_payment_flow_unaffected":0.046,"Tests\\Feature\\BillPaymentTest::test_generate_bill_positive_after_sale_added_to_total":0.112,"Tests\\Feature\\BillPaymentTest::test_generate_bill_rejects_non_numeric_after_sale":0.048,"Tests\\Feature\\ClientSpecialTest::test_batch_add_creates_specials":0.021,"Tests\\Feature\\ClientSpecialTest::test_batch_add_skips_existing_products":0.011,"Tests\\Feature\\ClientSpecialTest::test_batch_add_requires_non_empty_product_ids":0.006,"Tests\\Feature\\ClientSpecialTest::test_batch_add_forbidden_without_permission":0.007,"Tests\\Feature\\ClientSpecialTest::test_query_filters_by_product_name_keyword":0.008,"Tests\\Feature\\ClientSpecialTest::test_update_changes_sort_and_status":0.006,"Tests\\Feature\\ClientSpecialTest::test_delete_and_batch_delete":0.008,"Tests\\Feature\\ClientSpecialTest::test_batch_delete_requires_non_empty_ids":0.006,"Tests\\Feature\\MiniSpecialTest::test_guest_sees_specials_with_null_price":0.045,"Tests\\Feature\\MiniSpecialTest::test_store_sees_level_price":0.046,"Tests\\Feature\\MiniSpecialTest::test_disabled_special_and_off_shelf_product_excluded":0.058,"Tests\\Feature\\MiniSpecialTest::test_specials_sorted_by_sort_asc":0.087,"Tests\\Feature\\MiniSpecialTest::test_cart_quantity_attached_for_store":0.047,"Tests\\Feature\\MiniOnlinePaymentTest::test_aes_encryption_matches_demo_golden":0.002,"Tests\\Feature\\MiniOnlinePaymentTest::test_notify_envelope_round_trip":0.005,"Tests\\Feature\\MiniOnlinePaymentTest::test_swapped_key_config_fails_with_clear_message":0.004,"Tests\\Feature\\MiniWechatPaymentTest::test_create_wechat_payment_success":0.062,"Tests\\Feature\\MiniWechatPaymentTest::test_create_wechat_payment_gateway_failure_releases_bills":0.067,"Tests\\Feature\\MiniWechatPaymentTest::test_wechat_notify_settles_payment":0.056,"Tests\\Feature\\MiniWechatPaymentTest::test_wechat_notify_rejects_invalid_messages":0.056,"Tests\\Feature\\MiniWechatPaymentTest::test_wechat_notify_with_platform_cert_validates_signature":0.055,"Tests\\Feature\\MiniWechatPaymentTest::test_wechat_query_syncs_status":0.057,"Tests\\Feature\\MiniWechatPaymentTest::test_wangpu_channel_remains_default":0.051,"Tests\\Feature\\BillPaymentTest::test_payment_config_returns_pay_methods":0.047}} \ No newline at end of file diff --git a/app/Http/Controllers/Mini/PaymentController.php b/app/Http/Controllers/Mini/PaymentController.php index 62294ac..a80c17f 100644 --- a/app/Http/Controllers/Mini/PaymentController.php +++ b/app/Http/Controllers/Mini/PaymentController.php @@ -37,7 +37,14 @@ class PaymentController extends BaseMiniController return $value; }; + // 支付方式开关(Checkbox 配置自动转数组;未配置时默认全部启用) + $payMethods = site_config('pay.pay_methods'); + if (! is_array($payMethods)) { + $payMethods = ['wechat_qrcode', 'alipay_qrcode', 'bank', 'online']; + } + return $this->success([ + 'pay_methods' => array_values($payMethods), 'wechat_qrcode' => $resolve(site_config('pay.wechat_qrcode', '')), 'alipay_qrcode' => $resolve(site_config('pay.alipay_qrcode', '')), 'bank_info' => (string) site_config('pay.bank_info', ''), diff --git a/app/Services/OnlinePaymentService.php b/app/Services/OnlinePaymentService.php index 7b8d42a..ecdce00 100644 --- a/app/Services/OnlinePaymentService.php +++ b/app/Services/OnlinePaymentService.php @@ -395,12 +395,12 @@ class OnlinePaymentService */ protected function subAppid(): string { - $subAppid = (string) site_config('pay.wangpu_sub_appid', ''); + $subAppid = (string) site_config('wangpu.sub_appid', ''); if ($subAppid === '') { $subAppid = (string) config('services.wangpu.sub_appid', ''); } if ($subAppid === '') { - $subAppid = (string) config('services.wechat.mini.appid', ''); + $subAppid = $this->wechat->appid(); } return trim($subAppid); } @@ -410,7 +410,7 @@ class OnlinePaymentService */ protected function wxpayMchId(): string { - $mchId = (string) site_config('pay.wxpay_mch_id', ''); + $mchId = (string) site_config('wxpay.mch_id', ''); if ($mchId === '') { $mchId = (string) config('services.wxpay.mch_id', ''); } diff --git a/app/Services/WangpuPayService.php b/app/Services/WangpuPayService.php index 657704e..0967e41 100644 --- a/app/Services/WangpuPayService.php +++ b/app/Services/WangpuPayService.php @@ -16,7 +16,7 @@ use Illuminate\Support\Str; * - 整体以 JSON 信封 POST:{serialNo, version, timestamp, data, signature, extras, organizNo}; * - 应答/通知反向解密:商户私钥解 signature 得 AES 密钥,再用其解 data 得业务报文。 * - * 配置优先级:后台「系统设置 → 支付配置」(site_config pay.wangpu_*) > config/services.php(env) + * 配置优先级:后台「系统设置 → 旺铺支付」(site_config wangpu.*) > config/services.php(env) */ class WangpuPayService { @@ -279,7 +279,7 @@ class WangpuPayService */ protected function config(string $key): string { - $value = site_config('pay.wangpu_' . $key, ''); + $value = site_config('wangpu.' . $key, ''); if ($value === null || $value === '') { $value = config('services.wangpu.' . $key, ''); } diff --git a/app/Services/WechatMiniService.php b/app/Services/WechatMiniService.php index b7b2291..5c64299 100644 --- a/app/Services/WechatMiniService.php +++ b/app/Services/WechatMiniService.php @@ -22,8 +22,8 @@ class WechatMiniService */ public function code2session(string $code): string { - $appid = trim((string) config('services.wechat.mini.appid')); - $secret = trim((string) config('services.wechat.mini.secret')); + $appid = $this->appid(); + $secret = $this->config('mini_secret'); if ($appid === '' || $secret === '') { throw new RepositoryException('微信小程序未配置 AppID/Secret,请联系管理员'); } @@ -45,4 +45,28 @@ class WechatMiniService return $openid; } + + /** + * 小程序 AppID(在线支付下单 appid 兜底等场景复用) + */ + public function appid(): string + { + return $this->config('mini_appid'); + } + + /** + * 读取应用配置:后台站点配置(微信应用配置分组)优先,为空回退 config/services.php(env) + */ + protected function config(string $key): string + { + $value = site_config('wechat.' . $key, ''); + if ($value === null || $value === '') { + $value = match ($key) { + 'mini_appid' => config('services.wechat.mini.appid', ''), + 'mini_secret' => config('services.wechat.mini.secret', ''), + default => '', + }; + } + return trim((string) $value); + } } diff --git a/app/Services/WechatPayService.php b/app/Services/WechatPayService.php index 0ff8d6c..ab41407 100644 --- a/app/Services/WechatPayService.php +++ b/app/Services/WechatPayService.php @@ -15,7 +15,7 @@ use Throwable; * - 交易查询:GET /v3/pay/transactions/out-trade-no/{商户订单号} * - 支付通知:Wechatpay-Signature 验签(配置平台证书/公钥时)+ APIv3 密钥 AES-256-GCM 解密报文 * - * 配置优先级:后台「系统设置 → 支付配置」(site_config pay.wxpay_*) > config/services.php(env) + * 配置优先级:后台「系统设置 → 微信官方支付」(site_config wxpay.*) > config/services.php(env) */ class WechatPayService { @@ -212,6 +212,9 @@ class WechatPayService protected function appid(): string { $appid = $this->config('appid'); + if ($appid === '') { + $appid = (string) site_config('wechat.mini_appid', ''); + } if ($appid === '') { $appid = (string) config('services.wechat.mini.appid', ''); } @@ -246,7 +249,7 @@ class WechatPayService */ protected function config(string $key): string { - $value = site_config('pay.wxpay_' . $key, ''); + $value = site_config('wxpay.' . $key, ''); if ($value === null || $value === '') { $value = config('services.wxpay.' . $key, ''); } diff --git a/config/services.php b/config/services.php index 3335b56..00ceaaf 100644 --- a/config/services.php +++ b/config/services.php @@ -45,6 +45,7 @@ return [ /* * 微信小程序(登录 code2Session / 手机号授权),AppID/Secret 需业务方提供 + * 优先读取后台「系统设置 → 微信应用配置」(site_config wechat.mini_appid / wechat.mini_secret),为空时回退到这里的 env 配置 */ 'wechat' => [ 'mini' => [ @@ -63,7 +64,7 @@ return [ /* * 旺铺支付网关(统一下单B-JSAPI / 交易查询 / 后台通知) - * 优先读取后台「系统设置 → 支付配置」(site_config pay.wangpu_*),为空时回退到这里的 env 配置 + * 优先读取后台「系统设置 → 旺铺支付」(site_config wangpu.*),为空时回退到这里的 env 配置 */ 'wangpu' => [ 'base_url' => env('WANGPU_BASE_URL', ''), // 网关域名,如 https://pay.example.com @@ -79,7 +80,7 @@ return [ /* * 微信官方支付(APIv3 小程序 JSAPI,基于 EasyWeChat Pay) - * 优先读取后台「系统设置 → 支付配置」(site_config pay.wxpay_*),为空时回退到这里的 env 配置 + * 优先读取后台「系统设置 → 微信官方支付」(site_config wxpay.*),为空时回退到这里的 env 配置 * 密钥/证书支持:完整 PEM 文本、base64 单行、或以 file:// 开头的文件路径 */ 'wxpay' => [ diff --git a/database/seeders/SysDataSeeder.php b/database/seeders/SysDataSeeder.php index 085d515..09b05bd 100644 --- a/database/seeders/SysDataSeeder.php +++ b/database/seeders/SysDataSeeder.php @@ -17,7 +17,10 @@ class SysDataSeeder extends Seeder DB::table('sys_site_config_group')->insert([ ['id' => 1, 'title' => '网站设置', 'key' => 'web', 'remark' => '网站基础设置', 'created_at' => $date, 'updated_at' => $date], ['id' => 3, 'title' => '业务配置', 'key' => 'services', 'remark' => '业务附加配置', 'created_at' => $date, 'updated_at' => $date], - ['id' => 4, 'title' => '支付配置', 'key' => 'pay', 'remark' => '网站的支付配置', 'created_at' => $date, 'updated_at' => $date], + ['id' => 4, 'title' => '支付配置', 'key' => 'pay', 'remark' => '收款方式与在线支付渠道配置', 'created_at' => $date, 'updated_at' => $date], + ['id' => 5, 'title' => '旺铺支付', 'key' => 'wangpu', 'remark' => '旺铺支付网关配置(进件入网后由旺铺分配)', 'created_at' => $date, 'updated_at' => $date], + ['id' => 6, 'title' => '微信官方支付', 'key' => 'wxpay', 'remark' => '微信支付 APIv3 商户配置', 'created_at' => $date, 'updated_at' => $date], + ['id' => 7, 'title' => '微信应用配置', 'key' => 'wechat', 'remark' => '微信小程序/公众号应用凭证配置', 'created_at' => $date, 'updated_at' => $date], ]); DB::table('sys_site_config_items')->insert([ ['id' => 1, 'group_id' => 1, 'key' => 'title', 'title' => '网站标题', 'describe' => '网站标题,用于展示在网站logo旁边和登录页面以及网页title中', 'values' => 'Xin Admin', 'type' => 'Input','options' => "", 'sort' => 0, 'created_at' => $date, 'updated_at' => $date,], @@ -26,26 +29,35 @@ class SysDataSeeder extends Seeder ['id' => 4, 'group_id' => 1, 'key' => 'describe', 'title' => '网站描述', 'describe' => '网站的基本描述', 'values' => '没有描述', 'type' => 'TextArea','options' => "", 'sort' => 2, 'created_at' => $date, 'updated_at' => $date], ['id' => 7, 'group_id' => 3, 'key' => 'box_amount', 'title' => '周转筐金额', 'describe' => '周转筐的金额,用于附加业务金额的计算', 'values' => '', 'type' => 'InputNumber','props' => "min=0\nmax=10000\nstep=0.01", 'sort' => 0, 'created_at' => $date, 'updated_at' => $date], ['id' => 8, 'group_id' => 3, 'key' => 'tray_amount', 'title' => '周转托盘金额', 'describe' => '周转托盘的金额,用于附加金额的计算', 'values' => '', 'type' => 'InputNumber','props' => "min=0\nmax=10000\nstep=0.01", 'sort' => 1, 'created_at' => $date, 'updated_at' => $date], + // 支付配置(pay):收款方式与在线支付渠道 ['id' => 9, 'group_id' => 4, 'key' => 'wechat_qrcode', 'title' => '微信收款码', 'describe' => '微信收款码图片地址(在文件管理中上传收款码后复制图片链接,或直接填写文件ID),小程序付款页展示', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 0, 'created_at' => $date, 'updated_at' => $date], ['id' => 10, 'group_id' => 4, 'key' => 'alipay_qrcode', 'title' => '支付宝收款码', 'describe' => '支付宝收款码图片地址(在文件管理中上传收款码后复制图片链接,或直接填写文件ID),小程序付款页展示', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 1, 'created_at' => $date, 'updated_at' => $date], ['id' => 11, 'group_id' => 4, 'key' => 'bank_info', 'title' => '对公汇款信息', 'describe' => '对公账户汇款信息(户名、账号、开户行等),小程序付款页展示', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 2, 'created_at' => $date, 'updated_at' => $date], - ['id' => 12, 'group_id' => 4, 'key' => 'wangpu_base_url', 'title' => '旺铺网关地址', 'describe' => '旺铺支付网关域名(如 https://pay.example.com),在线支付下单/查询接口前缀', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 3, 'created_at' => $date, 'updated_at' => $date], - ['id' => 13, 'group_id' => 4, 'key' => 'wangpu_organiz_no', 'title' => '旺铺机构渠道号', 'describe' => '合作机构渠道号 organiz_no(旺铺分配)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 4, 'created_at' => $date, 'updated_at' => $date], - ['id' => 14, 'group_id' => 4, 'key' => 'wangpu_mer_no', 'title' => '旺铺内部商户号', 'describe' => '旺铺内部商户号 mer_no(进件入网后返回)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 5, 'created_at' => $date, 'updated_at' => $date], - ['id' => 15, 'group_id' => 4, 'key' => 'wangpu_mer_code', 'title' => '旺铺商户号', 'describe' => '商户号 mer_code(进件入网后返回)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 6, 'created_at' => $date, 'updated_at' => $date], - ['id' => 16, 'group_id' => 4, 'key' => 'wangpu_term_code', 'title' => '旺铺终端号', 'describe' => '终端号 term_code(进件入网后返回)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 7, 'created_at' => $date, 'updated_at' => $date], - ['id' => 17, 'group_id' => 4, 'key' => 'wangpu_public_key', 'title' => '旺铺平台公钥', 'describe' => '旺铺平台 RSA 公钥(base64 单行,不含 PEM 头尾),用于加密请求报文 AES 密钥,旺铺提供', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 8, 'created_at' => $date, 'updated_at' => $date], - ['id' => 18, 'group_id' => 4, 'key' => 'wangpu_sub_appid', 'title' => '旺铺下单子appid', 'describe' => '下单微信子 appid(sub_appid),留空则取小程序自身 appid', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 9, 'created_at' => $date, 'updated_at' => $date], - ['id' => 19, 'group_id' => 4, 'key' => 'wangpu_payway_code', 'title' => '旺铺支付方式代码', 'describe' => '支付方式代码 payway_code(小程序主扫必填,如 WECHAT_MINI),见旺铺数据词典', 'values' => 'WECHAT_MINI', 'type' => 'Input','options' => "", 'sort' => 10, 'created_at' => $date, 'updated_at' => $date], - ['id' => 20, 'group_id' => 4, 'key' => 'wangpu_private_key', 'title' => '商户RSA私钥', 'describe' => '商户 RSA 私钥(base64 单行,不含 PEM 头尾),用于解密网关应答/支付通知报文,请勿泄露', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 11, 'created_at' => $date, 'updated_at' => $date], - ['id' => 21, 'group_id' => 4, 'key' => 'online_channel', 'title' => '在线支付渠道', 'describe' => '小程序在线支付通道(二选一):旺铺支付网关 或 微信官方支付(APIv3),切换仅影响之后发起的支付单', 'values' => 'wangpu', 'type' => 'Radio','options' => "wangpu=旺铺支付\nwechat=微信官方支付", 'sort' => 12, 'created_at' => $date, 'updated_at' => $date], - ['id' => 22, 'group_id' => 4, 'key' => 'wxpay_mch_id', 'title' => '微信支付商户号', 'describe' => '微信支付商户号 mch_id(微信商户平台分配)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 13, 'created_at' => $date, 'updated_at' => $date], - ['id' => 23, 'group_id' => 4, 'key' => 'wxpay_appid', 'title' => '微信支付小程序appid', 'describe' => '下单小程序 appid(须与商户号绑定),留空则取小程序自身 appid', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 14, 'created_at' => $date, 'updated_at' => $date], - ['id' => 24, 'group_id' => 4, 'key' => 'wxpay_private_key', 'title' => '微信商户API私钥', 'describe' => '商户 API 私钥 apiclient_key.pem 内容(完整 PEM 或 base64 单行),用于请求签名,请勿泄露', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 15, 'created_at' => $date, 'updated_at' => $date], - ['id' => 25, 'group_id' => 4, 'key' => 'wxpay_certificate', 'title' => '微信商户API证书', 'describe' => '商户 API 证书 apiclient_cert.pem 内容(完整 PEM 或 base64 单行),请求签名序列号取自证书', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 16, 'created_at' => $date, 'updated_at' => $date], - ['id' => 26, 'group_id' => 4, 'key' => 'wxpay_secret_key', 'title' => '微信APIv3密钥', 'describe' => 'APIv3 密钥(32 位,商户平台自行设置),用于解密支付结果通知报文', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 17, 'created_at' => $date, 'updated_at' => $date], - ['id' => 27, 'group_id' => 4, 'key' => 'wxpay_platform_cert', 'title' => '微信平台证书/公钥', 'describe' => '微信支付平台证书或微信支付公钥内容(完整 PEM 或 base64 单行),用于回调验签,可留空(留空则以 APIv3 密钥解密结果为准)', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 18, 'created_at' => $date, 'updated_at' => $date], - ['id' => 28, 'group_id' => 4, 'key' => 'wxpay_platform_serial', 'title' => '微信平台证书序列号', 'describe' => '平台证书序列号或微信支付公钥ID(PUB_KEY_ID_ 开头),配合平台证书/公钥使用', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 19, 'created_at' => $date, 'updated_at' => $date], + ['id' => 21, 'group_id' => 4, 'key' => 'online_channel', 'title' => '在线支付渠道', 'describe' => '小程序在线支付通道(二选一):旺铺支付网关 或 微信官方支付(APIv3),切换仅影响之后发起的支付单', 'values' => 'wangpu', 'type' => 'Radio','options' => "wangpu=旺铺支付\nwechat=微信官方支付", 'sort' => 3, 'created_at' => $date, 'updated_at' => $date], + ['id' => 29, 'group_id' => 4, 'key' => 'pay_methods', 'title' => '支付方式开关', 'describe' => '小程序付款页启用的支付方式(勾选展示),接口 /mini/payment/config 返回 pay_methods 供小程序端控制展示', 'values' => '["wechat_qrcode","alipay_qrcode","bank","online"]', 'type' => 'Checkbox','options' => "wechat_qrcode=微信收款码\nalipay_qrcode=支付宝收款码\nbank=对公汇款\nonline=在线支付", 'sort' => 4, 'created_at' => $date, 'updated_at' => $date], + // 旺铺支付(wangpu):旺铺支付网关 + ['id' => 12, 'group_id' => 5, 'key' => 'base_url', 'title' => '旺铺网关地址', 'describe' => '旺铺支付网关域名(如 https://pay.example.com),在线支付下单/查询接口前缀', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 0, 'created_at' => $date, 'updated_at' => $date], + ['id' => 13, 'group_id' => 5, 'key' => 'organiz_no', 'title' => '旺铺机构渠道号', 'describe' => '合作机构渠道号 organiz_no(旺铺分配)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 1, 'created_at' => $date, 'updated_at' => $date], + ['id' => 14, 'group_id' => 5, 'key' => 'mer_no', 'title' => '旺铺内部商户号', 'describe' => '旺铺内部商户号 mer_no(进件入网后返回)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 2, 'created_at' => $date, 'updated_at' => $date], + ['id' => 15, 'group_id' => 5, 'key' => 'mer_code', 'title' => '旺铺商户号', 'describe' => '商户号 mer_code(进件入网后返回)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 3, 'created_at' => $date, 'updated_at' => $date], + ['id' => 16, 'group_id' => 5, 'key' => 'term_code', 'title' => '旺铺终端号', 'describe' => '终端号 term_code(进件入网后返回)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 4, 'created_at' => $date, 'updated_at' => $date], + ['id' => 17, 'group_id' => 5, 'key' => 'public_key', 'title' => '旺铺平台公钥', 'describe' => '旺铺平台 RSA 公钥(base64 单行,不含 PEM 头尾),用于加密请求报文 AES 密钥,旺铺提供', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 5, 'created_at' => $date, 'updated_at' => $date], + ['id' => 18, 'group_id' => 5, 'key' => 'sub_appid', 'title' => '旺铺下单子appid', 'describe' => '下单微信子 appid(sub_appid),留空则取小程序自身 appid', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 6, 'created_at' => $date, 'updated_at' => $date], + ['id' => 19, 'group_id' => 5, 'key' => 'payway_code', 'title' => '旺铺支付方式代码', 'describe' => '支付方式代码 payway_code(小程序主扫必填,如 WECHAT_MINI),见旺铺数据词典', 'values' => 'WECHAT_MINI', 'type' => 'Input','options' => "", 'sort' => 7, 'created_at' => $date, 'updated_at' => $date], + ['id' => 20, 'group_id' => 5, 'key' => 'private_key', 'title' => '商户RSA私钥', 'describe' => '商户 RSA 私钥(base64 单行,不含 PEM 头尾),用于解密网关应答/支付通知报文,请勿泄露', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 8, 'created_at' => $date, 'updated_at' => $date], + // 微信官方支付(wxpay):微信支付 APIv3 + ['id' => 22, 'group_id' => 6, 'key' => 'mch_id', 'title' => '微信支付商户号', 'describe' => '微信支付商户号 mch_id(微信商户平台分配)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 0, 'created_at' => $date, 'updated_at' => $date], + ['id' => 23, 'group_id' => 6, 'key' => 'appid', 'title' => '微信支付小程序appid', 'describe' => '下单小程序 appid(须与商户号绑定),留空则取小程序自身 appid', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 1, 'created_at' => $date, 'updated_at' => $date], + ['id' => 24, 'group_id' => 6, 'key' => 'private_key', 'title' => '微信商户API私钥', 'describe' => '商户 API 私钥 apiclient_key.pem 内容(完整 PEM 或 base64 单行),用于请求签名,请勿泄露', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 2, 'created_at' => $date, 'updated_at' => $date], + ['id' => 25, 'group_id' => 6, 'key' => 'certificate', 'title' => '微信商户API证书', 'describe' => '商户 API 证书 apiclient_cert.pem 内容(完整 PEM 或 base64 单行),请求签名序列号取自证书', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 3, 'created_at' => $date, 'updated_at' => $date], + ['id' => 26, 'group_id' => 6, 'key' => 'secret_key', 'title' => '微信APIv3密钥', 'describe' => 'APIv3 密钥(32 位,商户平台自行设置),用于解密支付结果通知报文', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 4, 'created_at' => $date, 'updated_at' => $date], + ['id' => 27, 'group_id' => 6, 'key' => 'platform_cert', 'title' => '微信平台证书/公钥', 'describe' => '微信支付平台证书或微信支付公钥内容(完整 PEM 或 base64 单行),用于回调验签,可留空(留空则以 APIv3 密钥解密结果为准)', 'values' => '', 'type' => 'TextArea','options' => "", 'sort' => 5, 'created_at' => $date, 'updated_at' => $date], + ['id' => 28, 'group_id' => 6, 'key' => 'platform_serial', 'title' => '微信平台证书序列号', 'describe' => '平台证书序列号或微信支付公钥ID(PUB_KEY_ID_ 开头),配合平台证书/公钥使用', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 6, 'created_at' => $date, 'updated_at' => $date], + // 微信应用配置(wechat):小程序与公众号应用凭证 + ['id' => 30, 'group_id' => 7, 'key' => 'mini_appid', 'title' => '小程序AppID', 'describe' => '微信小程序 AppID(wx.login 换 openid、在线支付下单使用),留空回退 env WECHAT_MINI_APPID', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 0, 'created_at' => $date, 'updated_at' => $date], + ['id' => 31, 'group_id' => 7, 'key' => 'mini_secret', 'title' => '小程序AppSecret', 'describe' => '微信小程序 AppSecret(code2session 登录凭证校验),请勿泄露,留空回退 env WECHAT_MINI_SECRET', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 1, 'created_at' => $date, 'updated_at' => $date], + ['id' => 32, 'group_id' => 7, 'key' => 'mp_appid', 'title' => '公众号AppID', 'describe' => '微信公众号 AppID(公众号消息/网页授权等扩展能力使用)', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 2, 'created_at' => $date, 'updated_at' => $date], + ['id' => 33, 'group_id' => 7, 'key' => 'mp_secret', 'title' => '公众号AppSecret', 'describe' => '微信公众号 AppSecret,请勿泄露', 'values' => '', 'type' => 'Input','options' => "", 'sort' => 3, 'created_at' => $date, 'updated_at' => $date], ]); // 字典类型初始数据 DB::table('sys_dict')->insert([ diff --git a/tests/Feature/BillPaymentTest.php b/tests/Feature/BillPaymentTest.php index 4a723fd..f9ffbb6 100644 --- a/tests/Feature/BillPaymentTest.php +++ b/tests/Feature/BillPaymentTest.php @@ -10,6 +10,9 @@ use App\Models\PurchaseOrderModel; use App\Models\StoreModel; use App\Models\StoreOrderModel; use Modules\SystemTool\Models\SysFileModel; +use Modules\SystemTool\Models\SysSiteConfigGroupModel; +use Modules\SystemTool\Models\SysSiteConfigItemsModel; +use Modules\SystemTool\Services\SysSiteConfigService; /** * 账单链路与支付:订单状态随业务链自动推进(采购单完成→配送中、生成账单→已完成); @@ -374,4 +377,35 @@ class BillPaymentTest extends ProcurementTestCase $this->assertStringContainsString('voucher/a.jpg', $data['payment']['voucher_urls'][0]); $this->assertStringContainsString('voucher/b.jpg', $data['payment']['voucher_urls'][1], '凭证顺序保持提交顺序'); } + + /** 支付配置接口:返回支付方式开关(未配置时默认全部启用,配置后按勾选项返回) */ + public function test_payment_config_returns_pay_methods(): void + { + $store = StoreModel::factory()->create(); + $this->actingAsMiniStore($store); + + // 未配置时默认全部启用 + $this->getJson('/mini/payment/config') + ->assertOk() + ->assertJsonPath('success', true) + ->assertJsonPath('data.pay_methods', ['wechat_qrcode', 'alipay_qrcode', 'bank', 'online']); + + // 后台勾选部分支付方式 + $group = SysSiteConfigGroupModel::create(['title' => '支付配置', 'key' => 'pay', 'remark' => '']); + SysSiteConfigItemsModel::create([ + 'group_id' => $group->id, + 'key' => 'pay_methods', + 'title' => '支付方式开关', + 'describe' => '', + 'values' => '["bank","online"]', + 'type' => 'Checkbox', + 'options' => '', + 'sort' => 0, + ]); + SysSiteConfigService::refreshSiteConfig(); + + $this->getJson('/mini/payment/config') + ->assertOk() + ->assertJsonPath('data.pay_methods', ['bank', 'online']); + } }