diff --git a/backend/internal/modules/order/lifecycle.go b/backend/internal/modules/order/lifecycle.go index 878f054..0f848a8 100644 --- a/backend/internal/modules/order/lifecycle.go +++ b/backend/internal/modules/order/lifecycle.go @@ -182,7 +182,7 @@ func (r *Repository) Create(ctx context.Context, renterID uint64, req CreateRequ if err != nil { return nil, err } - return r.FindForUser(ctx, renterID, createdID) + return r.FindForUser(ctx, renterID, createdID, req.DistributionSiteCode) } func loadShelfRatioTx(tx *gorm.DB, siteCode string, listingID uint64) (float64, uint64, error) { diff --git a/backend/internal/modules/order/queries.go b/backend/internal/modules/order/queries.go index af8a123..f8ab578 100644 --- a/backend/internal/modules/order/queries.go +++ b/backend/internal/modules/order/queries.go @@ -23,12 +23,13 @@ func (r *Repository) ListForUser(ctx context.Context, userID uint64, page, pageS } if code != "" { base = base.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", code). - Where("o.distribution_mode != ?", distribution.ModeTwoPartyDistributorReceive) + Where("o.owner_id = ? OR o.distribution_mode != ?", userID, distribution.ModeTwoPartyDistributorReceive) countBase = countBase.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", code). - Where("o.distribution_mode != ?", distribution.ModeTwoPartyDistributorReceive) + Where("o.owner_id = ? OR o.distribution_mode != ?", userID, distribution.ModeTwoPartyDistributorReceive) } else { - base = base.Where("o.distribution_site_id IS NULL OR o.distribution_site_id = 0 OR o.distribution_mode = ?", distribution.ModeTwoPartyDistributorReceive) - countBase = countBase.Where("o.distribution_site_id IS NULL OR o.distribution_site_id = 0 OR o.distribution_mode = ?", distribution.ModeTwoPartyDistributorReceive) + mainSiteCond := "o.owner_id = ? OR o.distribution_site_id IS NULL OR o.distribution_site_id = 0 OR o.distribution_mode = ?" + base = base.Where(mainSiteCond, userID, distribution.ModeTwoPartyDistributorReceive) + countBase = countBase.Where(mainSiteCond, userID, distribution.ModeTwoPartyDistributorReceive) } var total int64 @@ -67,10 +68,7 @@ func (r *Repository) ListSellerHandoffs(ctx context.Context, userID uint64, quer base = base.Where("o.status = ?", query.Status) } if query.SiteCode != "" { - base = base.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", query.SiteCode). - Where("o.distribution_mode != ?", distribution.ModeTwoPartyDistributorReceive) - } else { - base = base.Where("o.distribution_site_id IS NULL OR o.distribution_site_id = 0 OR o.distribution_mode = ?", distribution.ModeTwoPartyDistributorReceive) + base = base.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", query.SiteCode) } var total int64 @@ -102,10 +100,7 @@ func (r *Repository) ListSellerHandoffs(ctx context.Context, userID uint64, quer func (r *Repository) sellerHandoffMetrics(ctx context.Context, userID uint64, siteCode ...string) (SellerHandoffMetrics, error) { base := r.db.WithContext(ctx).Table("rental_orders AS o").Where("o.owner_id = ?", userID) if len(siteCode) > 0 && siteCode[0] != "" { - base = base.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", siteCode[0]). - Where("o.distribution_mode != ?", distribution.ModeTwoPartyDistributorReceive) - } else if len(siteCode) > 0 { - base = base.Where("o.distribution_site_id IS NULL OR o.distribution_site_id = 0 OR o.distribution_mode = ?", distribution.ModeTwoPartyDistributorReceive) + base = base.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", siteCode[0]) } var metrics SellerHandoffMetrics if err := base.Session(&gorm.Session{}).Where("o.status = ? AND o.handoff_status = ?", orderStatusPendingHandoff, handoffStatusPendingOwner).Count(&metrics.PendingHandoff).Error; err != nil { @@ -345,10 +340,10 @@ func (r *Repository) FindForUser(ctx context.Context, userID uint64, orderID uin code = strings.TrimSpace(siteCode[0]) } if code != "" { - query = query.Joins("INNER JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id AND ds.site_code = ?", code). - Where("o.distribution_mode != ?", distribution.ModeTwoPartyDistributorReceive) - } else if len(siteCode) > 0 { - query = query.Where("o.distribution_site_id IS NULL OR o.distribution_site_id = 0 OR o.distribution_mode = ?", distribution.ModeTwoPartyDistributorReceive) + query = query.Joins("LEFT JOIN distribution_sites AS ds ON ds.id = o.distribution_site_id"). + Where("o.owner_id = ? OR (ds.site_code = ? AND o.distribution_mode != ?)", userID, code, distribution.ModeTwoPartyDistributorReceive) + } else { + query = query.Where("o.owner_id = ? OR o.distribution_site_id IS NULL OR o.distribution_site_id = 0 OR o.distribution_mode = ?", userID, distribution.ModeTwoPartyDistributorReceive) } if err := query.First(&row).Error; err != nil { diff --git a/backend/internal/modules/order/repository_integration_test.go b/backend/internal/modules/order/repository_integration_test.go index 1c84138..8f89834 100644 --- a/backend/internal/modules/order/repository_integration_test.go +++ b/backend/internal/modules/order/repository_integration_test.go @@ -2322,9 +2322,49 @@ func TestListForUserAndFindForUserSiteIsolation(t *testing.T) { t.Fatalf("expected error accessing distRecvOrder under distribution site, got nil") } - // 7. FindForUser: distOrder CANNOT be accessed under main site mode ("") + // 7. FindForUser: distOrder CANNOT be accessed under main site mode ("") by renter _, err = repo.FindForUser(ctx, renter.ID, distOrder.ID, "") if err == nil { t.Fatalf("expected error accessing distOrder under main site mode, got nil") } + + // 8. Owner queries ListForUser under main site mode (""): MUST return all 3 orders! + ownerMainList, err := repo.ListForUser(ctx, owner.ID, 1, 20, "") + if err != nil { + t.Fatalf("ListForUser owner on main site err: %v", err) + } + if len(ownerMainList.Items) != 3 { + t.Fatalf("expected owner to see all 3 orders on main site, got %d", len(ownerMainList.Items)) + } + + // 9. Owner queries FindForUser for distOrder under main site mode (""): MUST succeed! + ownerDistItem, err := repo.FindForUser(ctx, owner.ID, distOrder.ID, "") + if err != nil || ownerDistItem.OrderNo != "RO_DIST_001" { + t.Fatalf("FindForUser distOrder by owner failed on main site: %v", err) + } + + // 10. Owner queries ListSellerHandoffs and sellerHandoffMetrics: should include subsite handoff orders + handoffOrder := model.RentalOrder{ + OrderNo: "RO_DIST_HANDOFF_001", + ListingID: listing.ID, + AccountID: account.ID, + OwnerID: owner.ID, + RenterID: renter.ID, + Status: orderStatusPendingHandoff, + HandoffStatus: handoffStatusPendingOwner, + DistributionSiteID: &site.ID, + DistributionMode: "site_self_sell", + } + db.Create(&handoffOrder) + + handoffList, err := repo.ListSellerHandoffs(ctx, owner.ID, SellerHandoffQuery{Page: 1, PageSize: 20}) + if err != nil { + t.Fatalf("ListSellerHandoffs err: %v", err) + } + if len(handoffList.Items) != 1 || handoffList.Items[0].OrderNo != "RO_DIST_HANDOFF_001" { + t.Fatalf("expected 1 handoff order for owner, got %+v", handoffList.Items) + } + if handoffList.Metrics.PendingHandoff != 1 { + t.Fatalf("expected PendingHandoff metric = 1, got %d", handoffList.Metrics.PendingHandoff) + } }