From 6d9f02d831e4436f02d01f46b373b4356a577ddc Mon Sep 17 00:00:00 2001 From: liu <2302563948@qq.com> Date: Mon, 17 Aug 2026 18:33:36 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=87=E8=B4=AD=E9=87=91=E9=A2=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .phpunit.result.cache | 2 +- .../Purchase/PurchaseOrderController.php | 50 ++++++++++-- tests/Feature/PurchaseEditTest.php | 80 ++++++++++++++++++- web/pages/purchase/order.tsx | 2 +- 4 files changed, 123 insertions(+), 11 deletions(-) diff --git a/.phpunit.result.cache b/.phpunit.result.cache index 90c26c5..170cdb7 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},"times":{"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.003,"Tests\\Feature\\ProductPriceTest::test_product_list_returns_price_for_store_level":0.015,"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.01,"Tests\\Feature\\StoreOrderTest::test_place_order_snapshots_level_price_and_recalculates":0.007,"Tests\\Feature\\StoreOrderTest::test_client_supplied_amount_is_ignored":0.007,"Tests\\Feature\\StoreOrderTest::test_product_without_level_price_rejected":0.007,"Tests\\Feature\\StoreOrderTest::test_cancel_only_pending_orders":0.015,"Tests\\Feature\\StoreOrderTest::test_summarized_order_cannot_be_cancelled":0.01,"Tests\\Feature\\StoreOrderTest::test_order_data_isolated_between_stores":0.015,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_orders_by_product":0.028,"Tests\\Feature\\PurchaseGenerateTest::test_generate_writes_back_order_status":0.02,"Tests\\Feature\\PurchaseGenerateTest::test_generate_without_pending_orders_fails":0.006,"Tests\\Feature\\PurchaseGenerateTest::test_generate_is_idempotent":0.033,"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.003,"Tests\\Feature\\ExportTest::test_export_xlsx_with_encoded_chinese_filename":0.039,"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.016,"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.007,"Tests\\Feature\\CartTest::test_duplicate_add_merges_quantity":0.01,"Tests\\Feature\\CartTest::test_off_shelf_product_rejected":0.006,"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.005,"Tests\\Feature\\CartTest::test_list_with_prices_amounts_and_totals":0.011,"Tests\\Feature\\CartTest::test_list_marks_off_shelf_item_unbuyable":0.011,"Tests\\Feature\\CartTest::test_empty_cart_returns_empty_items":0.005,"Tests\\Feature\\CartTest::test_update_quantity":0.008,"Tests\\Feature\\CartTest::test_update_other_users_item_rejected":0.009,"Tests\\Feature\\CartTest::test_update_missing_item_rejected":0.008,"Tests\\Feature\\CartTest::test_invalid_quantity_rejected":0.007,"Tests\\Feature\\CartTest::test_delete_item":0.007,"Tests\\Feature\\CartTest::test_delete_other_users_item_rejected":0.009,"Tests\\Feature\\CartTest::test_clear_only_own_cart":0.013,"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.017,"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.007,"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.012,"Tests\\Feature\\MiniAuthTest::test_login_rejects_unregistered_openid":0.002,"Tests\\Feature\\MiniAuthTest::test_register_binds_store_and_issues_token":0.019,"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.005,"Tests\\Feature\\MiniStoreTest::test_update_info_ignores_readonly_fields":0.005,"Tests\\Feature\\MiniStoreTest::test_requires_bound_store":0.007,"Tests\\Feature\\MiniStoreTest::test_update_info_validates_length":0.005,"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.015,"Tests\\Feature\\PurchaseGenerateTest::test_generate_with_selected_order_ids":0.028,"Tests\\Feature\\StoreOrderItemTest::test_place_order_snapshots_full_product_info":0.008,"Tests\\Feature\\StoreOrderItemTest::test_mini_detail_hides_cost_price":0.01,"Tests\\Feature\\StoreOrderItemTest::test_admin_detail_shows_cost_price_and_supplier":0.017,"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.017,"Tests\\Feature\\StoreOrderTest::test_soft_delete_only_cancelled_orders":0.023,"Tests\\Feature\\StoreOrderTest::test_soft_delete_rejected_for_non_cancelled_orders":0.071,"Tests\\Feature\\StoreOrderTest::test_soft_delete_twice_rejected":0.021,"Tests\\Feature\\PurchaseEditTest::test_detail_returns_store_matrix":0.031,"Tests\\Feature\\PurchaseEditTest::test_update_cell_syncs_order_item_and_totals":0.021,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_syncs_all_order_items":0.027,"Tests\\Feature\\PurchaseEditTest::test_update_row_weight_distributed_by_quantity":0.032,"Tests\\Feature\\PurchaseEditTest::test_update_row_requires_at_least_one_field":0.021,"Tests\\Feature\\PurchaseEditTest::test_update_cell_rejects_negative_quantity":0.026,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_order_items_into_header":0.03,"Tests\\Feature\\ReconciliationTest::test_build_excludes_unfinished_orders":0.016,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_product_attributes":0.022,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_to_product_catalog":0.019,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_returns_items_with_order_info":0.064,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_rejects_missing_params":0.029,"Tests\\Feature\\PurchaseEditTest::test_update_cell_weight_cascades_totals":0.025,"Tests\\Feature\\PurchaseEditTest::test_cell_sync_refreshes_snapshot_and_cascades":0.012,"Tests\\Feature\\PurchaseEditTest::test_edits_rejected_when_purchase_completed":0.031,"Tests\\Feature\\PurchaseEditTest::test_update_row_does_not_touch_manual_weight":0.027,"Tests\\Feature\\PurchaseEditTest::test_store_summary_returns_aggregated_items":0.022,"Tests\\Feature\\PurchaseEditTest::test_store_summary_aggregates_multiple_orders_with_weighted_price":0.025,"Tests\\Feature\\PurchaseEditTest::test_store_summary_rejects_missing_or_invalid_params":0.024,"Tests\\Feature\\ExportTest::test_export_invalid_type_rejected":0.016,"Tests\\Feature\\ExportTest::test_export_missing_purchase_rejected":0.006,"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.007,"Tests\\Feature\\ProductCategoryTest::test_create_category_under_second_level_rejected":0.009,"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.007,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_parent_category_rejected":0.007,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_leaf_category_ok":0.007,"Tests\\Feature\\ProductCategoryTest::test_mini_categories_returns_all_enabled_categories":0.005,"Tests\\Feature\\MiniBillTest::test_bill_list_derives_pay_state_and_settlement_date":0.009,"Tests\\Feature\\MiniBillTest::test_bill_list_summary_aggregates_unpaid":0.007,"Tests\\Feature\\MiniBillTest::test_bill_list_payable_filter":0.007,"Tests\\Feature\\MiniBillTest::test_bill_list_filters_by_bill_date_range":0.012,"Tests\\Feature\\MiniBillTest::test_bill_data_isolated_between_stores":0.008,"Tests\\Feature\\MiniBillTest::test_bill_detail_outputs_bill_items_and_orders":0.008,"Tests\\Feature\\StoreOrderTest::test_order_list_outputs_status_name_and_item_preview":0.014,"Tests\\Feature\\StoreOrderTest::test_order_list_filters_by_order_date_range":0.02,"Tests\\Feature\\StoreOrderTest::test_order_list_rejects_invalid_filters":0.009,"Tests\\Feature\\BillExportTest::test_export_merges_items_across_bills":0.057,"Tests\\Feature\\BillExportTest::test_export_filters_by_root_category":0.011,"Tests\\Feature\\BillExportTest::test_export_empty_category_rejected":0.028,"Tests\\Feature\\BillExportTest::test_export_requires_export_permission":0.01,"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.012,"Tests\\Feature\\BillExportTest::test_mini_export_requires_store_binding":0.005,"Tests\\Feature\\MiniNoticeTest::test_notice_list_includes_personal_and_broadcast":0.005,"Tests\\Feature\\MiniNoticeTest::test_broadcast_read_creates_personal_copy":0.008,"Tests\\Feature\\MiniNoticeTest::test_personal_notice_read_marks_directly":0.006,"Tests\\Feature\\MiniNoticeTest::test_other_users_notice_not_found":0.006,"Tests\\Feature\\StoreOrderTest::test_manual_status_flow_only_accept_and_cancel":0.022,"Tests\\Feature\\StoreOrderTest::test_manual_status_flow_rejects_delivery_and_completion":0.031,"Tests\\Feature\\StoreOrderTest::test_batch_status_only_accept_and_cancel":0.026,"Tests\\Feature\\BillPaymentTest::test_order_status_progresses_via_business_chain":0.037,"Tests\\Feature\\BillPaymentTest::test_manual_pay_accumulates_store_total_purchase_amount":0.026,"Tests\\Feature\\BillPaymentTest::test_payment_audit_pass_accumulates_store_total_purchase_amount":0.012,"Tests\\Feature\\BillPaymentTest::test_payment_audit_reject_does_not_accumulate":0.009,"Tests\\Feature\\MiniProductTest::test_product_detail_guest_sees_null_price":0.005,"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.006,"Tests\\Feature\\MiniProductTest::test_product_detail_off_shelf_or_missing_rejected":0.007,"Tests\\Feature\\MiniProductTest::test_product_list_store_user_sees_level_price":0.006,"Tests\\Feature\\MiniProductTest::test_product_list_guest_sees_null_price":0.007,"Tests\\Feature\\BillPaymentTest::test_admin_order_list_and_detail_show_bill_info":0.03,"Tests\\Feature\\BillPaymentTest::test_payment_detail_returns_voucher_urls":0.013,"Tests\\Feature\\StoreOrderTest::test_order_list_preview_includes_image_spec_and_unit":0.013,"Tests\\Feature\\ContainerReturnTest::test_press_containers_adds_amount_and_writes_record":0.021,"Tests\\Feature\\ContainerReturnTest::test_return_containers_deducts_amount":0.018,"Tests\\Feature\\ContainerReturnTest::test_mixed_sign_containers":0.019,"Tests\\Feature\\ContainerReturnTest::test_zero_containers_writes_no_record":0.018,"Tests\\Feature\\ContainerReturnTest::test_non_integer_containers_rejected":0.007,"Tests\\Feature\\ContainerReturnTest::test_manual_create_and_delete_routes_removed":0.01,"Tests\\Feature\\ContainerReturnTest::test_export_matrix_merges_same_day_and_zero_fills":0.009,"Tests\\Feature\\ContainerReturnTest::test_export_filters_by_selected_stores":0.008,"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.006,"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.009,"Tests\\Feature\\DashboardTest::test_overview_excludes_cancelled_orders":0.011,"Tests\\Feature\\DashboardTest::test_week_growth_rate":0.014,"Tests\\Feature\\DashboardTest::test_trend_covers_30_days_with_zero_filling":0.01,"Tests\\Feature\\DashboardTest::test_category_sales_grouped_by_category":0.012,"Tests\\Feature\\DashboardTest::test_top_products_aggregated_across_orders":0.012,"Tests\\Feature\\DashboardTest::test_top_stores_ranked_by_amount":0.011,"Tests\\Feature\\DashboardTest::test_purchase_amount_prefers_actual_over_estimate":0.009,"Tests\\Feature\\DashboardTest::test_recon_summary_and_receivable":0.011,"Tests\\Feature\\DashboardTest::test_latest_orders_limited_and_ordered":0.012,"Tests\\Feature\\DashboardTest::test_archives_count_active_records_only":0.011,"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.015,"Tests\\Feature\\ProductPriceTest::test_level_percent_update_notifies_level_stores":0.012,"Tests\\Feature\\ProductPriceTest::test_level_update_without_percent_change_sends_no_notice":0.007,"Tests\\Feature\\ProductPriceTest::test_level_percent_validation":0.01,"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.009,"Tests\\Feature\\ProductCostPriceTest::test_create_product_with_cost_price":0.01,"Tests\\Feature\\ProductCostPriceTest::test_batch_price_cost_row_update":0.019,"Tests\\Feature\\ProductCostPriceTest::test_price_matrix_includes_cost_and_level_price_columns":0.008,"Tests\\Feature\\ProductCostPriceTest::test_mini_order_uses_level_price":0.01,"Tests\\Feature\\ProductCostPriceTest::test_mini_cart_uses_level_price":0.027,"Tests\\Feature\\CartTest::test_store_level_missing_rejected":0.005,"Tests\\Feature\\StoreOrderTest::test_store_level_missing_rejected":0.011,"Tests\\Feature\\PurchaseEditTest::test_update_row_skips_catalog_sync_when_product_deleted":0.021,"Tests\\Feature\\PurchaseEditTest::test_store_item_add_creates_item_and_recalculates":0.027,"Tests\\Feature\\PurchaseEditTest::test_store_item_update_merges_multi_order_rows":0.04,"Tests\\Feature\\PurchaseEditTest::test_store_item_remove_deletes_and_recalculates":0.024,"Tests\\Feature\\StoreOrderItemTest::test_update_store_item_recalculates_totals":0.018,"Tests\\Feature\\StoreOrderItemTest::test_store_item_edits_rejected_when_purchase_completed":0.03,"Tests\\Feature\\StoreOrderItemTest::test_update_store_item_validates_negative_values":0.023,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_uses_level_percent_price":0.055,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_rejected_when_product_deleted":0.017,"Tests\\Feature\\ExportTest::test_export_lists_all_catalog_products_with_totals_row":0.02,"Tests\\Feature\\ExportTest::test_export_supplier_filter":0.021,"Tests\\Feature\\ExportTest::test_export_stores_multi_sheet":0.023,"Tests\\Feature\\ExportTest::test_export_stores_single_store":0.022,"Tests\\Feature\\ExportTest::test_export_stores_without_items_rejected":0.02,"Tests\\Feature\\ExportTest::test_export_suppliers_multi_sheet":0.022,"Tests\\Feature\\ExportTest::test_export_suppliers_single":0.02,"Tests\\Feature\\ExportTest::test_export_suppliers_without_items_rejected":0.021}} \ 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},"times":{"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.003,"Tests\\Feature\\ProductPriceTest::test_product_list_returns_price_for_store_level":0.008,"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.007,"Tests\\Feature\\StoreOrderTest::test_client_supplied_amount_is_ignored":0.007,"Tests\\Feature\\StoreOrderTest::test_product_without_level_price_rejected":0.007,"Tests\\Feature\\StoreOrderTest::test_cancel_only_pending_orders":0.011,"Tests\\Feature\\StoreOrderTest::test_summarized_order_cannot_be_cancelled":0.011,"Tests\\Feature\\StoreOrderTest::test_order_data_isolated_between_stores":0.013,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_orders_by_product":0.028,"Tests\\Feature\\PurchaseGenerateTest::test_generate_writes_back_order_status":0.019,"Tests\\Feature\\PurchaseGenerateTest::test_generate_without_pending_orders_fails":0.006,"Tests\\Feature\\PurchaseGenerateTest::test_generate_is_idempotent":0.02,"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.004,"Tests\\Feature\\ExportTest::test_export_xlsx_with_encoded_chinese_filename":0.04,"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.016,"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.006,"Tests\\Feature\\CartTest::test_duplicate_add_merges_quantity":0.008,"Tests\\Feature\\CartTest::test_off_shelf_product_rejected":0.006,"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.006,"Tests\\Feature\\CartTest::test_list_with_prices_amounts_and_totals":0.01,"Tests\\Feature\\CartTest::test_list_marks_off_shelf_item_unbuyable":0.01,"Tests\\Feature\\CartTest::test_empty_cart_returns_empty_items":0.005,"Tests\\Feature\\CartTest::test_update_quantity":0.008,"Tests\\Feature\\CartTest::test_update_other_users_item_rejected":0.009,"Tests\\Feature\\CartTest::test_update_missing_item_rejected":0.008,"Tests\\Feature\\CartTest::test_invalid_quantity_rejected":0.006,"Tests\\Feature\\CartTest::test_delete_item":0.008,"Tests\\Feature\\CartTest::test_delete_other_users_item_rejected":0.009,"Tests\\Feature\\CartTest::test_clear_only_own_cart":0.013,"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.006,"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.019,"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.005,"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.005,"Tests\\Feature\\MiniStoreTest::test_update_info_ignores_readonly_fields":0.006,"Tests\\Feature\\MiniStoreTest::test_requires_bound_store":0.007,"Tests\\Feature\\MiniStoreTest::test_update_info_validates_length":0.005,"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.011,"Tests\\Feature\\PurchaseGenerateTest::test_generate_with_selected_order_ids":0.021,"Tests\\Feature\\StoreOrderItemTest::test_place_order_snapshots_full_product_info":0.008,"Tests\\Feature\\StoreOrderItemTest::test_mini_detail_hides_cost_price":0.01,"Tests\\Feature\\StoreOrderItemTest::test_admin_detail_shows_cost_price_and_supplier":0.014,"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.02,"Tests\\Feature\\StoreOrderTest::test_soft_delete_only_cancelled_orders":0.019,"Tests\\Feature\\StoreOrderTest::test_soft_delete_rejected_for_non_cancelled_orders":0.044,"Tests\\Feature\\StoreOrderTest::test_soft_delete_twice_rejected":0.012,"Tests\\Feature\\PurchaseEditTest::test_detail_returns_store_matrix":0.023,"Tests\\Feature\\PurchaseEditTest::test_update_cell_syncs_order_item_and_totals":0.021,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_syncs_all_order_items":0.024,"Tests\\Feature\\PurchaseEditTest::test_update_row_weight_distributed_by_quantity":0.032,"Tests\\Feature\\PurchaseEditTest::test_update_row_requires_at_least_one_field":0.02,"Tests\\Feature\\PurchaseEditTest::test_update_cell_rejects_negative_quantity":0.02,"Tests\\Feature\\PurchaseGenerateTest::test_generate_aggregates_order_items_into_header":0.018,"Tests\\Feature\\ReconciliationTest::test_build_excludes_unfinished_orders":0.016,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_product_attributes":0.023,"Tests\\Feature\\PurchaseEditTest::test_update_row_syncs_to_product_catalog":0.019,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_returns_items_with_order_info":0.022,"Tests\\Feature\\PurchaseEditTest::test_cell_detail_rejects_missing_params":0.019,"Tests\\Feature\\PurchaseEditTest::test_update_cell_weight_cascades_totals":0.021,"Tests\\Feature\\PurchaseEditTest::test_cell_sync_refreshes_snapshot_and_cascades":0.012,"Tests\\Feature\\PurchaseEditTest::test_edits_rejected_when_purchase_completed":0.037,"Tests\\Feature\\PurchaseEditTest::test_update_row_does_not_touch_manual_weight":0.028,"Tests\\Feature\\PurchaseEditTest::test_store_summary_returns_aggregated_items":0.021,"Tests\\Feature\\PurchaseEditTest::test_store_summary_aggregates_multiple_orders_with_weighted_price":0.019,"Tests\\Feature\\PurchaseEditTest::test_store_summary_rejects_missing_or_invalid_params":0.022,"Tests\\Feature\\ExportTest::test_export_invalid_type_rejected":0.016,"Tests\\Feature\\ExportTest::test_export_missing_purchase_rejected":0.006,"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.007,"Tests\\Feature\\ProductCategoryTest::test_create_category_under_second_level_rejected":0.008,"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.008,"Tests\\Feature\\ProductCategoryTest::test_update_with_missing_parent_rejected":0.007,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_parent_category_rejected":0.007,"Tests\\Feature\\ProductCategoryTest::test_create_product_with_leaf_category_ok":0.007,"Tests\\Feature\\ProductCategoryTest::test_mini_categories_returns_all_enabled_categories":0.005,"Tests\\Feature\\MiniBillTest::test_bill_list_derives_pay_state_and_settlement_date":0.01,"Tests\\Feature\\MiniBillTest::test_bill_list_summary_aggregates_unpaid":0.016,"Tests\\Feature\\MiniBillTest::test_bill_list_payable_filter":0.007,"Tests\\Feature\\MiniBillTest::test_bill_list_filters_by_bill_date_range":0.012,"Tests\\Feature\\MiniBillTest::test_bill_data_isolated_between_stores":0.008,"Tests\\Feature\\MiniBillTest::test_bill_detail_outputs_bill_items_and_orders":0.009,"Tests\\Feature\\StoreOrderTest::test_order_list_outputs_status_name_and_item_preview":0.015,"Tests\\Feature\\StoreOrderTest::test_order_list_filters_by_order_date_range":0.018,"Tests\\Feature\\StoreOrderTest::test_order_list_rejects_invalid_filters":0.008,"Tests\\Feature\\BillExportTest::test_export_merges_items_across_bills":0.055,"Tests\\Feature\\BillExportTest::test_export_filters_by_root_category":0.011,"Tests\\Feature\\BillExportTest::test_export_empty_category_rejected":0.026,"Tests\\Feature\\BillExportTest::test_export_requires_export_permission":0.01,"Tests\\Feature\\BillExportTest::test_export_invalid_ids_rejected":0.01,"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.006,"Tests\\Feature\\MiniNoticeTest::test_broadcast_read_creates_personal_copy":0.009,"Tests\\Feature\\MiniNoticeTest::test_personal_notice_read_marks_directly":0.006,"Tests\\Feature\\MiniNoticeTest::test_other_users_notice_not_found":0.007,"Tests\\Feature\\StoreOrderTest::test_manual_status_flow_only_accept_and_cancel":0.022,"Tests\\Feature\\StoreOrderTest::test_manual_status_flow_rejects_delivery_and_completion":0.027,"Tests\\Feature\\StoreOrderTest::test_batch_status_only_accept_and_cancel":0.02,"Tests\\Feature\\BillPaymentTest::test_order_status_progresses_via_business_chain":0.022,"Tests\\Feature\\BillPaymentTest::test_manual_pay_accumulates_store_total_purchase_amount":0.027,"Tests\\Feature\\BillPaymentTest::test_payment_audit_pass_accumulates_store_total_purchase_amount":0.011,"Tests\\Feature\\BillPaymentTest::test_payment_audit_reject_does_not_accumulate":0.008,"Tests\\Feature\\MiniProductTest::test_product_detail_guest_sees_null_price":0.006,"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.006,"Tests\\Feature\\MiniProductTest::test_product_detail_off_shelf_or_missing_rejected":0.006,"Tests\\Feature\\MiniProductTest::test_product_list_store_user_sees_level_price":0.005,"Tests\\Feature\\MiniProductTest::test_product_list_guest_sees_null_price":0.006,"Tests\\Feature\\BillPaymentTest::test_admin_order_list_and_detail_show_bill_info":0.031,"Tests\\Feature\\BillPaymentTest::test_payment_detail_returns_voucher_urls":0.013,"Tests\\Feature\\StoreOrderTest::test_order_list_preview_includes_image_spec_and_unit":0.009,"Tests\\Feature\\ContainerReturnTest::test_press_containers_adds_amount_and_writes_record":0.02,"Tests\\Feature\\ContainerReturnTest::test_return_containers_deducts_amount":0.018,"Tests\\Feature\\ContainerReturnTest::test_mixed_sign_containers":0.018,"Tests\\Feature\\ContainerReturnTest::test_zero_containers_writes_no_record":0.019,"Tests\\Feature\\ContainerReturnTest::test_non_integer_containers_rejected":0.008,"Tests\\Feature\\ContainerReturnTest::test_manual_create_and_delete_routes_removed":0.016,"Tests\\Feature\\ContainerReturnTest::test_export_matrix_merges_same_day_and_zero_fills":0.008,"Tests\\Feature\\ContainerReturnTest::test_export_filters_by_selected_stores":0.007,"Tests\\Feature\\ContainerReturnTest::test_export_invalid_params_rejected":0.01,"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.006,"Tests\\Feature\\DashboardTest::test_empty_database_returns_zero_structure":0.009,"Tests\\Feature\\DashboardTest::test_overview_excludes_cancelled_orders":0.011,"Tests\\Feature\\DashboardTest::test_week_growth_rate":0.014,"Tests\\Feature\\DashboardTest::test_trend_covers_30_days_with_zero_filling":0.01,"Tests\\Feature\\DashboardTest::test_category_sales_grouped_by_category":0.011,"Tests\\Feature\\DashboardTest::test_top_products_aggregated_across_orders":0.014,"Tests\\Feature\\DashboardTest::test_top_stores_ranked_by_amount":0.012,"Tests\\Feature\\DashboardTest::test_purchase_amount_prefers_actual_over_estimate":0.01,"Tests\\Feature\\DashboardTest::test_recon_summary_and_receivable":0.011,"Tests\\Feature\\DashboardTest::test_latest_orders_limited_and_ordered":0.018,"Tests\\Feature\\DashboardTest::test_archives_count_active_records_only":0.012,"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.009,"Tests\\Feature\\ProductPriceTest::test_level_percent_update_notifies_level_stores":0.012,"Tests\\Feature\\ProductPriceTest::test_level_update_without_percent_change_sends_no_notice":0.008,"Tests\\Feature\\ProductPriceTest::test_level_percent_validation":0.009,"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.01,"Tests\\Feature\\ProductCostPriceTest::test_price_matrix_includes_cost_and_level_price_columns":0.007,"Tests\\Feature\\ProductCostPriceTest::test_mini_order_uses_level_price":0.007,"Tests\\Feature\\ProductCostPriceTest::test_mini_cart_uses_level_price":0.009,"Tests\\Feature\\CartTest::test_store_level_missing_rejected":0.006,"Tests\\Feature\\StoreOrderTest::test_store_level_missing_rejected":0.007,"Tests\\Feature\\PurchaseEditTest::test_update_row_skips_catalog_sync_when_product_deleted":0.024,"Tests\\Feature\\PurchaseEditTest::test_store_item_add_creates_item_and_recalculates":0.024,"Tests\\Feature\\PurchaseEditTest::test_store_item_update_merges_multi_order_rows":0.018,"Tests\\Feature\\PurchaseEditTest::test_store_item_remove_deletes_and_recalculates":0.025,"Tests\\Feature\\StoreOrderItemTest::test_update_store_item_recalculates_totals":0.019,"Tests\\Feature\\StoreOrderItemTest::test_store_item_edits_rejected_when_purchase_completed":0.023,"Tests\\Feature\\StoreOrderItemTest::test_update_store_item_validates_negative_values":0.018,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_uses_level_percent_price":0.018,"Tests\\Feature\\StoreOrderItemTest::test_add_store_item_rejected_when_product_deleted":0.029,"Tests\\Feature\\ExportTest::test_export_lists_all_catalog_products_with_totals_row":0.021,"Tests\\Feature\\ExportTest::test_export_supplier_filter":0.025,"Tests\\Feature\\ExportTest::test_export_stores_multi_sheet":0.023,"Tests\\Feature\\ExportTest::test_export_stores_single_store":0.023,"Tests\\Feature\\ExportTest::test_export_stores_without_items_rejected":0.021,"Tests\\Feature\\ExportTest::test_export_suppliers_multi_sheet":0.022,"Tests\\Feature\\ExportTest::test_export_suppliers_single":0.022,"Tests\\Feature\\ExportTest::test_export_suppliers_without_items_rejected":0.022,"Tests\\Feature\\PurchaseEditTest::test_update_row_cost_change_reprices_items_by_store_level":0.024,"Tests\\Feature\\PurchaseEditTest::test_update_row_without_cost_change_keeps_item_price":0.025}} \ No newline at end of file diff --git a/app/Http/Controllers/Purchase/PurchaseOrderController.php b/app/Http/Controllers/Purchase/PurchaseOrderController.php index e30867a..ca0ef1d 100644 --- a/app/Http/Controllers/Purchase/PurchaseOrderController.php +++ b/app/Http/Controllers/Purchase/PurchaseOrderController.php @@ -670,6 +670,8 @@ class PurchaseOrderController extends BaseController /** * 商品行修改:品名/供应商/包规/单位/成本(同步更新商品档案;商品已删除则跳过档案同步) + * 成本价变化时,按各门店客户等级的上浮比例重算明细单价与金额(无等级按成本价兜底), + * 并级联重算涉及订单与采购单汇总 * @throws Throwable */ #[PutRoute(route: '/{id}/row/{productId}', authorize: 'update', where: ['id' => '[0-9]+', 'productId' => '[0-9]+'])] @@ -692,8 +694,34 @@ class PurchaseOrderController extends BaseController if ($items->isEmpty()) { throw new RepositoryException('该采购单下无此商品的订货明细'); } + + // 成本价是否变化(未变化时保留明细单价,避免覆盖单元格/单品的手工改价) + $newCost = bcadd((string) $validated['cost_price'], '0', 2); + $costChanged = bccomp($newCost, bcadd((string) $items->first()->cost_price, '0', 2), 2) !== 0; + + // 成本变化 → 按门店等级上浮比例重算单价(一次性取回涉及门店的等级,避免逐行查询) + $levelPercents = []; + if ($costChanged) { + $levelPercents = StoreModel::withTrashed() + ->with('level:id,percent') + ->whereIn('id', $items->pluck('store_id')->unique()) + ->get(['id', 'level_id']) + ->mapWithKeys(static fn (StoreModel $store) => [ + $store->id => (float) ($store->level?->percent ?? 0), + ]) + ->all(); + } + foreach ($items as $item) { - $item->fill($validated)->save(); + $item->fill($validated); + if ($costChanged) { + $item->price = CustomerLevelModel::calcLevelPrice( + $newCost, + $levelPercents[(int) $item->store_id] ?? 0, + ); + $item->amount = bcmul($item->price, (string) $item->quantity, 2); + } + $item->save(); } // 同步保存到商品档案(软删除商品跳过,明细照常更新) @@ -709,14 +737,20 @@ class PurchaseOrderController extends BaseController ]); } - app(PurchaseItemService::class)->recalcPurchase($purchase->id); + $service = app(PurchaseItemService::class); + // 成本变化会引起明细金额变动,涉及订单需逐一重算 + if ($costChanged) { + foreach ($items->pluck('order_id')->unique() as $orderId) { + $service->recalcOrder((int) $orderId); + } + } + $service->recalcPurchase($purchase->id); - return $this->success( - ['count' => $items->count()], - $productSynced - ? '已同步 ' . $items->count() . ' 条订货明细与商品档案' - : '已同步 ' . $items->count() . ' 条订货明细;商品已删除,档案未同步' - ); + $message = '已同步 ' . $items->count() . ' 条订货明细' + . ($productSynced ? '与商品档案' : ';商品已删除,档案未同步') + . ($costChanged ? ';门店单价已按等级上浮比例重算' : ''); + + return $this->success(['count' => $items->count()], $message); }); } diff --git a/tests/Feature/PurchaseEditTest.php b/tests/Feature/PurchaseEditTest.php index 8ee3cb5..ceb8779 100644 --- a/tests/Feature/PurchaseEditTest.php +++ b/tests/Feature/PurchaseEditTest.php @@ -200,7 +200,7 @@ class PurchaseEditTest extends ProcurementTestCase 'cost_price' => 25, ])->assertOk() ->assertJsonPath('success', true) - ->assertJsonPath('msg', '已同步 2 条订货明细;商品已删除,档案未同步'); + ->assertJsonPath('msg', '已同步 2 条订货明细;商品已删除,档案未同步;门店单价已按等级上浮比例重算'); $this->assertSame('已删商品新名', StoreOrderItemModel::first()->product_name, '订货明细照常更新'); $this->assertNotSame('已删商品新名', $product->fresh()->name, '商品档案不同步'); @@ -287,6 +287,84 @@ class PurchaseEditTest extends ProcurementTestCase $this->assertSame('80.00', (string) $purchase->estimate_amount, '8 包 × 每包成本 10.00(称重仅参考,不参与金额)'); } + /** 行级成本修改 → 明细单价按各门店等级上浮比例重算,订单与采购单汇总级联 */ + public function test_update_row_cost_change_reprices_items_by_store_level(): void + { + // 门店A 上浮 0%(售价=成本),门店B 上浮 50% + $levelA = CustomerLevelModel::factory()->create(['percent' => 0]); + $levelB = CustomerLevelModel::factory()->create(['percent' => 50]); + $storeA = StoreModel::factory()->create(['level_id' => $levelA->id]); + $storeB = StoreModel::factory()->create(['level_id' => $levelB->id]); + $product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON, 'cost_price' => 10]); + + foreach ([[$storeA, 2], [$storeB, 3]] as [$store, $qty]) { + $this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create()); + $this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => $qty]]]) + ->assertJsonPath('success', true); + } + StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]); + + $this->actingAsSysUser(); + $this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()]) + ->assertJsonPath('success', true); + $purchase = PurchaseOrderModel::first(); + + // 下单时快照:A 店 10.00(10 上浮 0%),B 店 15.00(10 上浮 50%) + $itemA = StoreOrderItemModel::where('store_id', $storeA->id)->first(); + $itemB = StoreOrderItemModel::where('store_id', $storeB->id)->first(); + $this->assertSame('10.00', (string) $itemA->price); + $this->assertSame('15.00', (string) $itemB->price); + + // 行修改成本 10 → 20:单价按各店等级上浮比例重算 + $this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [ + 'product_name' => $product->name, + 'supplier_id' => SupplierModel::factory()->create()->id, + 'product_spec' => $product->spec, + 'unit' => $product->unit, + 'cost_price' => 20, + ])->assertOk() + ->assertJsonPath('success', true) + ->assertJsonPath('msg', '已同步 2 条订货明细与商品档案;门店单价已按等级上浮比例重算'); + + $itemA->refresh(); + $this->assertSame('20.00', (string) $itemA->cost_price); + $this->assertSame('20.00', (string) $itemA->price, 'A 店:20 上浮 0% = 20.00'); + $this->assertSame('40.00', (string) $itemA->amount, '20.00 × 2'); + + $itemB->refresh(); + $this->assertSame('30.00', (string) $itemB->price, 'B 店:20 上浮 50% = 30.00'); + $this->assertSame('90.00', (string) $itemB->amount, '30.00 × 3'); + + $this->assertSame('40.00', (string) StoreOrderModel::where('store_id', $storeA->id)->first()->total_amount); + $this->assertSame('90.00', (string) StoreOrderModel::where('store_id', $storeB->id)->first()->total_amount); + $this->assertSame('100.00', (string) $purchase->fresh()->estimate_amount, '5 包 × 新成本 20.00'); + } + + /** 行修改未改成本 → 明细单价保持不变(不覆盖单元格的手工改价) */ + public function test_update_row_without_cost_change_keeps_item_price(): void + { + [$purchase, $product, $stores] = $this->buildPurchase(); + $this->actingAsSysUser(); + + // 先通过单元格手工改价 10 → 12 + $item = StoreOrderItemModel::where('store_id', $stores[0]->id)->first(); + $this->putJson("/purchase/order/cell/{$item->id}", ['quantity' => 2, 'price' => 12]) + ->assertJsonPath('success', true); + + // 行修改只改品名(成本不变) + $this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [ + 'product_name' => '只改品名', + 'supplier_id' => SupplierModel::factory()->create()->id, + 'product_spec' => $product->spec, + 'unit' => $product->unit, + 'cost_price' => 10, + ])->assertOk() + ->assertJsonPath('success', true) + ->assertJsonPath('msg', '已同步 2 条订货明细与商品档案'); + + $this->assertSame('12.00', (string) $item->fresh()->price, '成本未变时保留手工改价'); + } + /** 门店购买详情-新增单品:挂靠最新一笔订单,汇总级联重算;重复添加拒绝 */ public function test_store_item_add_creates_item_and_recalculates(): void { diff --git a/web/pages/purchase/order.tsx b/web/pages/purchase/order.tsx index e57cc6e..6ba1611 100644 --- a/web/pages/purchase/order.tsx +++ b/web/pages/purchase/order.tsx @@ -1184,7 +1184,7 @@ const PurchaseOrderPage: React.FC = () => { ]} >