@@ -1122,6 +1122,213 @@ final class OrderDetailsDataSourceTests: XCTestCase {
11221122 XCTAssertNil ( seeReceiptRow)
11231123 XCTAssertNil ( seeLegacyReceiptRow)
11241124 }
1125+
1126+ // MARK: - wooShippingShipments Tests
1127+
1128+ func test_wooShippingShipments_is_initially_empty( ) {
1129+ // Given
1130+ let order = Order . fake ( )
1131+ let dataSource = OrderDetailsDataSource ( order: order,
1132+ storageManager: storageManager,
1133+ cardPresentPaymentsConfiguration: Mocks . configuration,
1134+ receiptEligibilityUseCase: MockReceiptEligibilityUseCase ( ) )
1135+
1136+ // Then
1137+ XCTAssertTrue ( dataSource. wooShippingShipments. isEmpty)
1138+ }
1139+
1140+ func test_populateShipments_with_empty_data_results_in_empty_shipments( ) {
1141+ // Given
1142+ let order = Order . fake ( )
1143+ let dataSource = OrderDetailsDataSource ( order: order,
1144+ storageManager: storageManager,
1145+ cardPresentPaymentsConfiguration: Mocks . configuration,
1146+ receiptEligibilityUseCase: MockReceiptEligibilityUseCase ( ) )
1147+ let labels : [ ShippingLabel ] = [ ]
1148+ let shipments : WooShippingShipments = [ : ]
1149+
1150+ // When
1151+ dataSource. populateShipments ( labels: labels, shipments: shipments)
1152+
1153+ // Then
1154+ XCTAssertTrue ( dataSource. wooShippingShipments. isEmpty)
1155+ }
1156+
1157+ func test_populateShipments_with_valid_data_creates_shipments( ) {
1158+ // Given
1159+ let order = makeOrder ( )
1160+ let dataSource = OrderDetailsDataSource ( order: order,
1161+ storageManager: storageManager,
1162+ cardPresentPaymentsConfiguration: Mocks . configuration,
1163+ receiptEligibilityUseCase: MockReceiptEligibilityUseCase ( ) )
1164+
1165+ let shippingLabel1 = ShippingLabel . fake ( ) . copy ( siteID: order. siteID,
1166+ orderID: order. orderID,
1167+ shipmentID: " 1 " ,
1168+ dateCreated: Date ( ) , status: . purchased)
1169+ let shippingLabel2 = ShippingLabel . fake ( ) . copy ( siteID: order. siteID,
1170+ orderID: order. orderID,
1171+ shipmentID: " 0 " ,
1172+ dateCreated: Date ( timeIntervalSinceNow: - 3600 ) , status: . purchased)
1173+ let labels = [ shippingLabel1, shippingLabel2]
1174+
1175+ let orderItem0 = order. items [ 0 ]
1176+ let orderItem1 = order. items [ 1 ]
1177+ storageManager. insertSampleProduct ( readOnlyProduct: Product . fake ( ) . copy ( siteID: order. siteID, productID: orderItem0. productID) )
1178+ storageManager. insertSampleProduct ( readOnlyProduct: Product . fake ( ) . copy ( siteID: order. siteID, productID: orderItem1. productID) )
1179+
1180+ let shipmentItem1 = WooShippingShipmentItem . fake ( ) . copy ( id: orderItem0. itemID, subItems: [ " sub1 " , " sub2 " ] )
1181+ let shipmentItem2 = WooShippingShipmentItem . fake ( ) . copy ( id: orderItem1. itemID, subItems: [ " sub3 " ] )
1182+ let shipments : WooShippingShipments = [
1183+ " 0 " : [ shipmentItem1] ,
1184+ " 1 " : [ shipmentItem2]
1185+ ]
1186+
1187+ // When
1188+ dataSource. populateShipments ( labels: labels, shipments: shipments)
1189+
1190+ // Then
1191+ XCTAssertEqual ( dataSource. wooShippingShipments. count, 2 )
1192+
1193+ // First shipment ("0" comes before "1" in sorted order)
1194+ let firstShipment = dataSource. wooShippingShipments [ 0 ]
1195+ XCTAssertEqual ( firstShipment. index, " 0 " )
1196+ XCTAssertEqual ( firstShipment. shippingLabel, shippingLabel2)
1197+ XCTAssertEqual ( firstShipment. items. count, 1 )
1198+ XCTAssertEqual ( firstShipment. items [ 0 ] . quantity, 2 ) // 2 subItems
1199+
1200+ // Second shipment
1201+ let secondShipment = dataSource. wooShippingShipments [ 1 ]
1202+ XCTAssertEqual ( secondShipment. index, " 1 " )
1203+ XCTAssertEqual ( secondShipment. shippingLabel, shippingLabel1)
1204+ XCTAssertEqual ( secondShipment. items. count, 1 )
1205+ XCTAssertEqual ( secondShipment. items [ 0 ] . quantity, 1 ) // 1 subItem
1206+ }
1207+
1208+ func test_populateShipments_with_no_matching_shipping_labels_creates_shipments_without_labels( ) {
1209+ // Given
1210+ let order = makeOrder ( )
1211+ let dataSource = OrderDetailsDataSource ( order: order,
1212+ storageManager: storageManager,
1213+ cardPresentPaymentsConfiguration: Mocks . configuration,
1214+ receiptEligibilityUseCase: MockReceiptEligibilityUseCase ( ) )
1215+
1216+ let labels : [ ShippingLabel ] = [ ]
1217+ let shipmentItem1 = WooShippingShipmentItem . fake ( ) . copy ( id: order. items [ 0 ] . itemID, subItems: [ " sub1 " ] )
1218+ let shipments : WooShippingShipments = [
1219+ " 0 " : [ shipmentItem1]
1220+ ]
1221+
1222+ // When
1223+ dataSource. populateShipments ( labels: labels, shipments: shipments)
1224+
1225+ // Then
1226+ XCTAssertEqual ( dataSource. wooShippingShipments. count, 1 )
1227+
1228+ let shipment = dataSource. wooShippingShipments [ 0 ]
1229+ XCTAssertEqual ( shipment. index, " 0 " )
1230+ XCTAssertNil ( shipment. shippingLabel)
1231+ }
1232+
1233+ func test_populateShipments_prioritizes_non_refunded_labels( ) {
1234+ // Given
1235+ let order = makeOrder ( )
1236+ let dataSource = OrderDetailsDataSource ( order: order,
1237+ storageManager: storageManager,
1238+ cardPresentPaymentsConfiguration: Mocks . configuration,
1239+ receiptEligibilityUseCase: MockReceiptEligibilityUseCase ( ) )
1240+
1241+ let refundedLabel = ShippingLabel . fake ( ) . copy ( siteID: order. siteID,
1242+ orderID: order. orderID,
1243+ shipmentID: " 0 " ,
1244+ dateCreated: Date ( ) , status: . purchased,
1245+ refund: ShippingLabelRefund . fake ( ) )
1246+ let nonRefundedLabel = ShippingLabel . fake ( ) . copy ( siteID: order. siteID,
1247+ orderID: order. orderID,
1248+ shipmentID: " 0 " ,
1249+ dateCreated: Date ( timeIntervalSinceNow: - 3600 ) , status: . purchased,
1250+ refund: nil )
1251+ let labels = [ refundedLabel, nonRefundedLabel]
1252+
1253+ let shipmentItem1 = WooShippingShipmentItem . fake ( ) . copy ( id: order. items [ 0 ] . itemID, subItems: [ " sub1 " ] )
1254+ let shipments : WooShippingShipments = [
1255+ " 0 " : [ shipmentItem1]
1256+ ]
1257+
1258+ // When
1259+ dataSource. populateShipments ( labels: labels, shipments: shipments)
1260+
1261+ // Then
1262+ XCTAssertEqual ( dataSource. wooShippingShipments. count, 1 )
1263+
1264+ let shipment = dataSource. wooShippingShipments [ 0 ]
1265+ XCTAssertEqual ( shipment. index, " 0 " )
1266+ XCTAssertEqual ( shipment. shippingLabel, nonRefundedLabel) // Should prioritize non-refunded
1267+ }
1268+
1269+ func test_populateShipments_uses_most_recent_label_when_all_refunded( ) {
1270+ // Given
1271+ let order = makeOrder ( )
1272+ let dataSource = OrderDetailsDataSource ( order: order,
1273+ storageManager: storageManager,
1274+ cardPresentPaymentsConfiguration: Mocks . configuration,
1275+ receiptEligibilityUseCase: MockReceiptEligibilityUseCase ( ) )
1276+
1277+ let olderRefundedLabel = ShippingLabel . fake ( ) . copy ( siteID: order. siteID,
1278+ orderID: order. orderID,
1279+ shipmentID: " 0 " ,
1280+ dateCreated: Date ( timeIntervalSinceNow: - 3600 ) , status: . purchased,
1281+ refund: ShippingLabelRefund . fake ( ) )
1282+ let newerRefundedLabel = ShippingLabel . fake ( ) . copy ( siteID: order. siteID,
1283+ orderID: order. orderID,
1284+ shipmentID: " 0 " ,
1285+ dateCreated: Date ( ) , status: . purchased,
1286+ refund: ShippingLabelRefund . fake ( ) )
1287+ let labels = [ olderRefundedLabel, newerRefundedLabel]
1288+
1289+ let shipmentItem1 = WooShippingShipmentItem . fake ( ) . copy ( id: order. items [ 0 ] . itemID, subItems: [ ] )
1290+ let shipments : WooShippingShipments = [
1291+ " 0 " : [ shipmentItem1]
1292+ ]
1293+
1294+ // When
1295+ dataSource. populateShipments ( labels: labels, shipments: shipments)
1296+
1297+ // Then
1298+ XCTAssertEqual ( dataSource. wooShippingShipments. count, 1 )
1299+
1300+ let shipment = dataSource. wooShippingShipments [ 0 ]
1301+ XCTAssertEqual ( shipment. index, " 0 " )
1302+ XCTAssertEqual ( shipment. shippingLabel, newerRefundedLabel) // Should use newer refunded label
1303+ }
1304+
1305+ func test_populateShipments_handles_shipments_with_no_subitems( ) {
1306+ // Given
1307+ let order = makeOrder ( )
1308+ let dataSource = OrderDetailsDataSource ( order: order,
1309+ storageManager: storageManager,
1310+ cardPresentPaymentsConfiguration: Mocks . configuration,
1311+ receiptEligibilityUseCase: MockReceiptEligibilityUseCase ( ) )
1312+
1313+ let labels : [ ShippingLabel ] = [ ]
1314+ let orderItem = order. items [ 0 ]
1315+ storageManager. insertSampleProduct ( readOnlyProduct: Product . fake ( ) . copy ( siteID: order. siteID, productID: orderItem. productID) )
1316+ let shipmentItemNoSubItems = WooShippingShipmentItem . fake ( ) . copy ( id: orderItem. itemID, subItems: [ ] )
1317+ let shipments : WooShippingShipments = [
1318+ " 0 " : [ shipmentItemNoSubItems]
1319+ ]
1320+
1321+ // When
1322+ dataSource. populateShipments ( labels: labels, shipments: shipments)
1323+
1324+ // Then
1325+ XCTAssertEqual ( dataSource. wooShippingShipments. count, 1 )
1326+
1327+ let shipment = dataSource. wooShippingShipments [ 0 ]
1328+ XCTAssertEqual ( shipment. index, " 0 " )
1329+ XCTAssertEqual ( shipment. items. count, 1 )
1330+ XCTAssertEqual ( shipment. items [ 0 ] . quantity, 1 ) // Should default to 1 when no subItems
1331+ }
11251332}
11261333
11271334// MARK: - Test Data
@@ -1131,6 +1338,12 @@ private extension OrderDetailsDataSourceTests {
11311338 MockOrders ( ) . makeOrder ( items: [ makeOrderItem ( ) , makeOrderItem ( ) ] , fees: [ OrderFeeLine . fake ( ) ] )
11321339 }
11331340
1341+ func makeOrder( items: [ OrderItem ] = [ ] , fees: [ OrderFeeLine ] = [ ] ) -> Order {
1342+ let defaultItems = items. isEmpty ? [ makeOrderItem ( ) , makeOrderItem ( ) ] : items
1343+ let defaultFees = fees. isEmpty ? [ OrderFeeLine . fake ( ) ] : fees
1344+ return MockOrders ( ) . makeOrder ( items: defaultItems, fees: defaultFees)
1345+ }
1346+
11341347 func makeOrderItem( ) -> OrderItem {
11351348 OrderItem ( itemID: 1 ,
11361349 name: " Order Item Name " ,
@@ -1217,7 +1430,6 @@ private extension OrderDetailsDataSourceTests {
12171430 func insert( _ readOnlyPlugin: Yosemite . SitePlugin ) {
12181431 let plugin = storage. insertNewObject ( ofType: StorageSitePlugin . self)
12191432 plugin. update ( with: readOnlyPlugin)
1220- storage. saveIfNeeded ( )
12211433 }
12221434
12231435 /// Finds first section with a given title from the provided data source.
0 commit comments