Merge branch 'feature/free-shipping-setting' into develop
This commit is contained in:
commit
4e7453a188
369
src/core/fixtures/merchandise.json
Normal file
369
src/core/fixtures/merchandise.json
Normal file
@ -0,0 +1,369 @@
|
||||
[{
|
||||
"model": "core.product",
|
||||
"pk": 10,
|
||||
"fields": {
|
||||
"category": 2,
|
||||
"name": "BLTC Mug",
|
||||
"subtitle": "Camper Vacuum Mug",
|
||||
"description": "Camp mug is made of double-wall stainless steel, designed to keep drinks hot or cold for hours.",
|
||||
"checkout_limit": 20,
|
||||
"visible_in_listings": false,
|
||||
"sorting": null,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 10,
|
||||
"name": "Blue - 12 oz.",
|
||||
"sku": "REPLACE_4001",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 10,
|
||||
"image": "products/images/bltc_mug_blue_12_oz.jpg"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"model": "core.product",
|
||||
"pk": 11,
|
||||
"fields": {
|
||||
"category": 2,
|
||||
"name": "BLTC Pull-over Hoodie",
|
||||
"subtitle": "Classic BLTC Logo front left and Steam/Waves on back",
|
||||
"description": "ComfortBlend Hoodie - Screen. EcoSmart® 7.8-oz poly-cotton blend hoodie features a front pouch pocket and two-ply hood with matching drawcord. Rib-knit cuffs and waistband ensure all-day comfort and warmth.",
|
||||
"checkout_limit": 20,
|
||||
"visible_in_listings": false,
|
||||
"sorting": null,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 11,
|
||||
"name": "Blue",
|
||||
"sku": "REPLACE_4002",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 11,
|
||||
"image": "products/images/bltc_pullover_hoodie_blue_front.jpg"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 11,
|
||||
"image": "products/images/bltc_pullover_hoodie_blue_back.jpg"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"model": "core.product",
|
||||
"pk": 12,
|
||||
"fields": {
|
||||
"category": 2,
|
||||
"name": "BLTC T-Shirt",
|
||||
"subtitle": "Logo T-Shirt with Steam/Waves on back",
|
||||
"description": "5.5 oz. DryBlend 50/50 T-Shirt - Screen. The 5.5-oz 50/50 cotton/polyester blend fabric is moisture-wicking.",
|
||||
"checkout_limit": 20,
|
||||
"visible_in_listings": false,
|
||||
"sorting": null,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 12,
|
||||
"name": "Heather Red",
|
||||
"sku": "REPLACE_4003",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 12,
|
||||
"name": "Heather Blue",
|
||||
"sku": "REPLACE_4004",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 12,
|
||||
"image": "products/images/bltc_tshirt_blue_front.jpg"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 12,
|
||||
"image": "products/images/bltc_tshirt_blue_back.jpg"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 12,
|
||||
"image": "products/images/bltc_tshirt_red_front.jpg"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 12,
|
||||
"image": "products/images/bltc_tshirt_red_back.jpg"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"model": "core.product",
|
||||
"pk": 13,
|
||||
"fields": {
|
||||
"category": 2,
|
||||
"name": "BLTC Trucker Cap",
|
||||
"subtitle": "Washed Cotton Mesh Back Cap with Logo",
|
||||
"description": "Soft washed cotton gives this trucker hat an appealing vintage look. Designed with ventilated mesh back panels and a front twill sweatband for comfort.",
|
||||
"checkout_limit": 20,
|
||||
"visible_in_listings": false,
|
||||
"sorting": null,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 13,
|
||||
"name": "Black and White",
|
||||
"sku": "REPLACE_4005",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 13,
|
||||
"image": "products/images/bltc_trucker_cap_black_and_white.jpg"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"model": "core.product",
|
||||
"pk": 14,
|
||||
"fields": {
|
||||
"category": 2,
|
||||
"name": "BLTC Zip-up Hoodie",
|
||||
"subtitle": "Classic BLTC Cafe Logo without the extra branding",
|
||||
"description": "Made from a 7.1-oz, 52/48 cotton/polyester blend. Includes a spacious hood with drawcords and metal grommets. Interior phone pocket with headphone cord port.",
|
||||
"checkout_limit": 20,
|
||||
"visible_in_listings": false,
|
||||
"sorting": null,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 14,
|
||||
"name": "Forest Green/Silver Embroidered",
|
||||
"sku": "REPLACE_4006",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 14,
|
||||
"name": "Navy Blue/Silver Embroidered",
|
||||
"sku": "REPLACE_4007",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 14,
|
||||
"name": "Black/Gold Embroidered",
|
||||
"sku": "REPLACE_4008",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 14,
|
||||
"image": "products/images/bltc_zipup_hoodie_black_gold.jpg"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 14,
|
||||
"image": "products/images/bltc_zipup_hoodie_green_silver.jpg"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 14,
|
||||
"image": "products/images/bltc_zipup_hoodie_navy_silver.jpg"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"model": "core.product",
|
||||
"pk": 15,
|
||||
"fields": {
|
||||
"category": 2,
|
||||
"name": "PT Coffee Cap",
|
||||
"subtitle": "Embroidered Buttonless Cap",
|
||||
"description": "These caps feature a buttonless design that won't interfere with headsets/headphones. The low profile fit and adjustable fabric strap with hook-and-loop closure helps create a more comfortable fit.",
|
||||
"checkout_limit": 20,
|
||||
"visible_in_listings": false,
|
||||
"sorting": null,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 15,
|
||||
"name": "Navy Blue with Red Embroidered Print",
|
||||
"sku": "REPLACE_4009",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 15,
|
||||
"image": "products/images/pt_coffee_cap_navy.jpg"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"model": "core.product",
|
||||
"pk": 16,
|
||||
"fields": {
|
||||
"category": 2,
|
||||
"name": "PT Coffee Cup",
|
||||
"subtitle": "Bean/Leaf Logo Neo Vacuum Insulated Cup",
|
||||
"description": "Designed to keep drinks hot or cold for hours. A great cup for enjoying wine, tea, coffee, hot chocolate, and more!",
|
||||
"checkout_limit": 20,
|
||||
"visible_in_listings": false,
|
||||
"sorting": null,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 16,
|
||||
"name": "Black and Gold 10 oz.",
|
||||
"sku": "REPLACE_4010",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 16,
|
||||
"name": "White and Black 10 oz.",
|
||||
"sku": "REPLACE_4011",
|
||||
"price": null,
|
||||
"weight": "00:oz",
|
||||
"track_inventory": true,
|
||||
"stock": 0,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 16,
|
||||
"image": "products/images/pt_coffee_cup_black_gold_10_oz.jpg"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productphoto",
|
||||
"pk": null,
|
||||
"fields": {
|
||||
"product": 16,
|
||||
"image": "products/images/pt_coffee_cup_white_black_10_oz.jpg"
|
||||
}
|
||||
}]
|
||||
271
src/core/fixtures/new_coffee_variants.json
Normal file
271
src/core/fixtures/new_coffee_variants.json
Normal file
@ -0,0 +1,271 @@
|
||||
[{
|
||||
"model": "core.productvariant",
|
||||
"pk": 10,
|
||||
"fields": {
|
||||
"product": 1,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87431",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 11,
|
||||
"fields": {
|
||||
"product": 1,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87430",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 12,
|
||||
"fields": {
|
||||
"product": 2,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87429",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 13,
|
||||
"fields": {
|
||||
"product": 2,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87428",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 14,
|
||||
"fields": {
|
||||
"product": 3,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87427",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 15,
|
||||
"fields": {
|
||||
"product": 3,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87426",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 16,
|
||||
"fields": {
|
||||
"product": 4,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87425",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 17,
|
||||
"fields": {
|
||||
"product": 4,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87424",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 18,
|
||||
"fields": {
|
||||
"product": 5,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87423",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 19,
|
||||
"fields": {
|
||||
"product": 5,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87422",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 20,
|
||||
"fields": {
|
||||
"product": 6,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87421",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 21,
|
||||
"fields": {
|
||||
"product": 6,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87420",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 22,
|
||||
"fields": {
|
||||
"product": 7,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87419",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 23,
|
||||
"fields": {
|
||||
"product": 7,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87418",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 24,
|
||||
"fields": {
|
||||
"product": 8,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87417",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 25,
|
||||
"fields": {
|
||||
"product": 8,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87416",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 26,
|
||||
"fields": {
|
||||
"product": 9,
|
||||
"name": "12 oz",
|
||||
"sku": "REPLACE_87467",
|
||||
"price": "12.00",
|
||||
"weight": "12.0:oz",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 1,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}, {
|
||||
"model": "core.productvariant",
|
||||
"pk": 27,
|
||||
"fields": {
|
||||
"product": 9,
|
||||
"name": "5 lb",
|
||||
"sku": "REPLACE_87486",
|
||||
"price": "75.00",
|
||||
"weight": "5.0:lb",
|
||||
"track_inventory": false,
|
||||
"stock": null,
|
||||
"sorting": 3,
|
||||
"created_at": "2022-02-23T18:06:57.624Z",
|
||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||
}
|
||||
}]
|
||||
18
src/core/migrations/0005_sitesettings_free_shipping_min.py
Normal file
18
src/core/migrations/0005_sitesettings_free_shipping_min.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.0.2 on 2022-11-05 00:02
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0004_alter_coupon_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='sitesettings',
|
||||
name='free_shipping_min',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True),
|
||||
),
|
||||
]
|
||||
23
src/core/migrations/0006_productvariant_sorting_and_more.py
Normal file
23
src/core/migrations/0006_productvariant_sorting_and_more.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.0.2 on 2022-11-05 15:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0005_sitesettings_free_shipping_min'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='productvariant',
|
||||
name='sorting',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sitesettings',
|
||||
name='free_shipping_min',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, help_text='Minimum dollar amount in the cart subtotal to qualify for free shipping', max_digits=12, null=True),
|
||||
),
|
||||
]
|
||||
17
src/core/migrations/0007_alter_productvariant_options.py
Normal file
17
src/core/migrations/0007_alter_productvariant_options.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Generated by Django 4.0.2 on 2022-11-05 16:13
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0006_productvariant_sorting_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='productvariant',
|
||||
options={'ordering': ['sorting', 'weight']},
|
||||
),
|
||||
]
|
||||
19
src/core/migrations/0008_productvariant_image.py
Normal file
19
src/core/migrations/0008_productvariant_image.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.0.2 on 2022-11-05 17:26
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0007_alter_productvariant_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='productvariant',
|
||||
name='image',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.productphoto'),
|
||||
),
|
||||
]
|
||||
@ -71,6 +71,14 @@ class ProductCategory(models.Model):
|
||||
verbose_name_plural = 'Product Categories'
|
||||
|
||||
|
||||
class ProductManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().prefetch_related(
|
||||
'productphoto_set',
|
||||
'options'
|
||||
)
|
||||
|
||||
|
||||
class Product(models.Model):
|
||||
category = models.ForeignKey(
|
||||
ProductCategory,
|
||||
@ -92,6 +100,8 @@ class Product(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
objects = ProductManager()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@ -124,6 +134,12 @@ class ProductVariant(models.Model):
|
||||
on_delete=models.CASCADE,
|
||||
related_name='variants'
|
||||
)
|
||||
image = models.ForeignKey(
|
||||
'ProductPhoto',
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='+',
|
||||
null=True
|
||||
)
|
||||
name = models.CharField(max_length=255)
|
||||
sku = models.CharField(max_length=255, unique=True)
|
||||
stripe_id = models.CharField(max_length=255, blank=True)
|
||||
@ -145,6 +161,7 @@ class ProductVariant(models.Model):
|
||||
null=True,
|
||||
validators=[MinValueValidator(0)]
|
||||
)
|
||||
sorting = models.PositiveIntegerField(blank=True, null=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
@ -155,7 +172,7 @@ class ProductVariant(models.Model):
|
||||
return f'{self.product}: {self.name}'
|
||||
|
||||
class Meta:
|
||||
ordering = ['weight']
|
||||
ordering = ['sorting', 'weight']
|
||||
|
||||
|
||||
class ProductOption(models.Model):
|
||||
@ -491,6 +508,13 @@ class SiteSettings(SingletonBase):
|
||||
related_name='+',
|
||||
on_delete=models.SET_NULL
|
||||
)
|
||||
free_shipping_min = models.DecimalField(
|
||||
max_digits=settings.DEFAULT_MAX_DIGITS,
|
||||
decimal_places=settings.DEFAULT_DECIMAL_PLACES,
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text='Minimum dollar amount in the cart subtotal to qualify for free shipping'
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return 'Site Settings'
|
||||
|
||||
@ -23,5 +23,17 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="object__panel">
|
||||
<div class="object__item panel__header panel__header--flex">
|
||||
<h4>Site Settings</h4>
|
||||
<a href="{% url 'dashboard:settings-update' site_settings.pk %}" class="action-button order__fulfill">Edit</a>
|
||||
</div>
|
||||
<div class="panel__item">
|
||||
<p>USPS User ID: {{ site_settings.usps_user_id }}</p>
|
||||
<p>Default shipping rate: {{ site_settings.default_shipping_rate }}</p>
|
||||
<p>Free shipping min: ${{ site_settings.free_shipping_min }}</p>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
{% endblock %}
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
</figure>
|
||||
<span>{{product.sku}}</span>
|
||||
<span>{{item.quantity}}</span>
|
||||
<span>${{item.variant.price}}</span>
|
||||
<span>${{item.unit_price}}</span>
|
||||
<span>${{item.get_total}}</span>
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
18
src/dashboard/templates/dashboard/settings_form.html
Normal file
18
src/dashboard/templates/dashboard/settings_form.html
Normal file
@ -0,0 +1,18 @@
|
||||
{% extends "dashboard.html" %}
|
||||
|
||||
{% block content %}
|
||||
<article class="product">
|
||||
<header class="object__header">
|
||||
<h1>Update Site Settings</h1>
|
||||
</header>
|
||||
<section class="object__panel">
|
||||
<form class="panel__item" method="POST" action="{% url 'dashboard:settings-update' settings.pk %}">
|
||||
{% csrf_token %}
|
||||
{{form.as_p}}
|
||||
<p class="form__submit">
|
||||
<input class="action-button" type="submit" value="Save changes"> or <a href="{% url 'dashboard:config' %}">cancel</a>
|
||||
</p>
|
||||
</form>
|
||||
</section>
|
||||
</article>
|
||||
{% endblock %}
|
||||
@ -12,6 +12,11 @@ urlpatterns = [
|
||||
views.DashboardConfigView.as_view(),
|
||||
name='config'
|
||||
),
|
||||
path(
|
||||
'settings/<int:pk>/update/',
|
||||
views.SiteSettingsUpdateView.as_view(),
|
||||
name='settings-update'
|
||||
),
|
||||
path(
|
||||
'catalog/',
|
||||
views.CatalogView.as_view(),
|
||||
|
||||
@ -37,7 +37,8 @@ from core.models import (
|
||||
ShippingRate,
|
||||
Transaction,
|
||||
TrackingNumber,
|
||||
Coupon
|
||||
Coupon,
|
||||
SiteSettings
|
||||
)
|
||||
|
||||
from core import (
|
||||
@ -88,6 +89,15 @@ class DashboardConfigView(TemplateView):
|
||||
return context
|
||||
|
||||
|
||||
class SiteSettingsUpdateView(UpdateView):
|
||||
model = SiteSettings
|
||||
context_object_name = 'settings'
|
||||
template_name = 'dashboard/settings_form.html'
|
||||
fields = '__all__'
|
||||
success_url = reverse_lazy('dashboard:config')
|
||||
success_message = 'Settings saved.'
|
||||
|
||||
|
||||
class CatalogView(ListView):
|
||||
model = ProductCategory
|
||||
context_object_name = 'category_list'
|
||||
|
||||
@ -9,9 +9,13 @@ const productItemImages = document.querySelectorAll('.product__with-img-swap')
|
||||
|
||||
productItemImages.forEach(productItemImage => {
|
||||
productItemImage.addEventListener('mouseover', event => {
|
||||
[event.target.src, event.target.dataset.altimgSrc] = valueSwap(event.target.src, event.target.dataset.altimgSrc)
|
||||
if (event.target.dataset.altimgSrc != '') {
|
||||
[event.target.src, event.target.dataset.altimgSrc] = valueSwap(event.target.src, event.target.dataset.altimgSrc)
|
||||
}
|
||||
})
|
||||
productItemImage.addEventListener('mouseout', event => {
|
||||
[event.target.src, event.target.dataset.altimgSrc] = valueSwap(event.target.src, event.target.dataset.altimgSrc)
|
||||
if (event.target.dataset.altimgSrc != '') {
|
||||
[event.target.src, event.target.dataset.altimgSrc] = valueSwap(event.target.src, event.target.dataset.altimgSrc)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -6,10 +6,12 @@ from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.shortcuts import redirect, reverse
|
||||
from django.urls import reverse_lazy
|
||||
from django.core.cache import cache
|
||||
from django.db.models import OuterRef, Q, Subquery
|
||||
|
||||
from core.models import (
|
||||
Product, ProductVariant, OrderLine, Coupon, ShippingRate
|
||||
Product, ProductVariant, OrderLine, Coupon, ShippingRate,
|
||||
SiteSettings
|
||||
)
|
||||
from core.usps import USPSApi
|
||||
from core import (
|
||||
@ -58,6 +60,7 @@ class CartItem:
|
||||
|
||||
class Cart:
|
||||
item_class = CartItem
|
||||
site_settings = SiteSettings.load()
|
||||
|
||||
def __init__(self, request):
|
||||
self.request = request
|
||||
@ -101,8 +104,15 @@ class Cart:
|
||||
for item in self:
|
||||
if item['variant'].track_inventory:
|
||||
if item['quantity'] > item['variant'].stock:
|
||||
messages.warning(request, 'Quantity added exceeds available stock.')
|
||||
if item['quantity'] > item['variant'].product.checkout_limit:
|
||||
messages.warning(request, 'Quantity exceeds checkout limit.')
|
||||
item['quantity'] = item['variant'].product.checkout_limit
|
||||
continue
|
||||
messages.warning(request, 'Quantity exceeds available stock.')
|
||||
item['quantity'] = item['variant'].stock
|
||||
elif item['quantity'] > item['variant'].product.checkout_limit:
|
||||
messages.warning(request, 'Quantity exceeds checkout limit.')
|
||||
item['quantity'] = item['variant'].product.checkout_limit
|
||||
self.save()
|
||||
|
||||
def remove(self, pk):
|
||||
@ -160,6 +170,10 @@ class Cart:
|
||||
return containers
|
||||
|
||||
def get_shipping_cost(self, container=None):
|
||||
free_shipping_min = self.site_settings.free_shipping_min
|
||||
if self.get_total_price() >= free_shipping_min:
|
||||
return Decimal('0.00')
|
||||
|
||||
if container is None:
|
||||
container = self.session.get('shipping_container').container
|
||||
|
||||
|
||||
@ -54,6 +54,7 @@
|
||||
<input type="submit" value="Apply" class="action-button">
|
||||
</p>
|
||||
</form>
|
||||
<h5>Free shipping on orders over ${{ site_settings.free_shipping_min|floatformat:"2" }}</h5>
|
||||
<div class="cart__table-wrapper">
|
||||
<table class="cart__totals">
|
||||
<tr>
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
{{item.customer_note}}
|
||||
</td>
|
||||
<td>{{item.quantity}}</td>
|
||||
<td>${{product.price}}</td>
|
||||
<td>${{item.unit_price}}</td>
|
||||
<td>${{item.get_total}}</td>
|
||||
{% endwith %}
|
||||
</tr>
|
||||
|
||||
@ -75,7 +75,11 @@
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>Shipping</td>
|
||||
<td>${{ cart.get_shipping_cost }}</small></td>
|
||||
{% if cart.get_total_price >= site_settings.free_shipping_min %}
|
||||
<td>Free!</td>
|
||||
{% else %}
|
||||
<td>${{ cart.get_shipping_cost }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total</th>
|
||||
|
||||
@ -178,6 +178,11 @@ class ProductCategoryDetailView(DetailView):
|
||||
Q(visible_in_listings=True),
|
||||
Q(variants__track_inventory=False) |
|
||||
Q(variants__track_inventory=True) & Q(variants__stock__gt=0)
|
||||
).prefetch_related(
|
||||
Prefetch(
|
||||
'variants',
|
||||
queryset=ProductVariant.objects.all().order_by('sorting', 'weight')
|
||||
)
|
||||
).distinct()
|
||||
)
|
||||
)
|
||||
@ -192,6 +197,11 @@ class ProductListView(ListView):
|
||||
queryset = Product.objects.filter(
|
||||
visible_in_listings=True,
|
||||
category__main_category=True
|
||||
).prefetch_related(
|
||||
Prefetch(
|
||||
'variants',
|
||||
queryset=ProductVariant.objects.all().order_by('sorting', 'weight')
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@ -206,7 +216,7 @@ class ProductDetailView(FormMixin, DetailView):
|
||||
track_inventory=True,
|
||||
stock__gt=0
|
||||
)
|
||||
)
|
||||
).order_by('name')
|
||||
options = ProductOption.objects.filter(products__pk=self.object.pk)
|
||||
if form_class is None:
|
||||
form_class = self.get_form_class()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user