Here is a quick take to ponder, as well as my write-up on Junction Tables in that link.
-- drop table products;
create table products
( prodId int auto_increment primary key, -- sku, code, whatever
isAssembly int not null, -- bool, whatever, for quick retrieval of just them
descr varchar(255) not null,
price decimal(10,2) not null -- varies here over time, but not in orderLines (frozen there)
);
-- drop table assemblies;
create table assemblies
( -- this assemblies table is to give a description, and to be one of the two anchors to the Junction table
-- but Orders still emanate from the products table
ashId int auto_increment primary key, -- trying to keep the column name clean
descr varchar(255) not null -- 'October Chocolate Package'
);
-- drop table orders;
create table orders
( ordId int auto_increment primary key,
ordDate datetime not null
-- etc customer blah blah blah
);
-- drop table orderLines;
create table orderLines
( id int auto_increment primary key,
ordId int not null,
prodId int not null, -- a product. Period. Can be an assembled product or not
seq int not null,
qty int not null,
price decimal(10,2) not null, -- the frozen price upon placing the order
CONSTRAINT fk_ol_orders FOREIGN KEY (ordId) REFERENCES orders(ordId),
CONSTRAINT fk_ol_products FOREIGN KEY (prodId) REFERENCES products(prodId)
);
-- drop table paJunction;
create table paJunction
( -- product/assembly junction table
-- one row here for each product that is in an assembly
id int auto_increment primary key,
prodId int not null,
ashId int not null,
qty int not null, -- how many prods go in that assembly
unique key(prodId,ashId), -- no dupes allowed
unique key(ashId,prodId), -- no dupes allowed
CONSTRAINT fk_paJ_products FOREIGN KEY (prodId) REFERENCES products(prodId),
CONSTRAINT fk_paJ_assemblies FOREIGN KEY (ashId) REFERENCES assemblies(ashId)
);
It would give you great flexibility in having month-over-month tweaks to your packages (or assemblies) of the month with new assemblies created. And allowing for re-use of old ones you want to promote as oh so special again with minimal effort.
Pricing history is maintained.
Allows the user to put whatever they want in the shopping cart.
I am sure sure the assemblies would need a visual for some people seeing this. I could put a few examples together.
The main takeaways are the use of Junction tables, and ordering out of on products table.