diff --git a/b2/INV b/b2/INV new file mode 100644 index 0000000..af6a39d --- /dev/null +++ b/b2/INV @@ -0,0 +1,2 @@ +FOO R101X CT 1234 1 USD 0 1 0.1 10 0.8 100 6 +FOO R101X-T TR 1234 3000 USD 0 3000 13 diff --git a/b2/db.c b/b2/db.c index ad1afc4..e15717c 100644 --- a/b2/db.c +++ b/b2/db.c @@ -158,6 +158,16 @@ void part_finalize(struct part *part, const struct action *act) } +void part_add_stock(struct part *part, struct stock *stock) +{ + if (!part->stock) { + part->stock = stock; + return; + } + yyerrorf("part %s %s already has stock", part->domain, part->name); +} + + void part_dump(FILE *file, const struct part *part) { const struct param *p; diff --git a/b2/db.h b/b2/db.h index 7125320..d5e92e4 100644 --- a/b2/db.h +++ b/b2/db.h @@ -28,28 +28,57 @@ struct currency { struct currency *next; }; +/* + * If quantity increases, next entry is next higher discount. + * If quantity decreases, next entries are prices after reaching the large + * quantity. + * + * Examples: + * + * An order of 12 units with the prices below + * + * a) 1 0.5 10 4.0 100 30.0 + * b) 1 0.5 10 4.0 1 0.4 100 30.0 + * + * would cost + * + * a) 1*4.0+2*0.5 = 5.0 + * b) 1*4.0+2*0.4 = 4.8 + */ + struct price { int qty; /* order quantity */ double value; /* per quantity cost */ - const struct currency *curr; - int fract; /* 0 if > qty at same price; 1 if multiples of qty */ - struct price *next; /* next lower qty */ + struct price *next; /* next qty */ }; struct provider { const char *name; double shipping; /* S&H cost */ - double minimum; /* minimum order */ + double minimum; /* value of minimum order, before S&H */ const struct currency *curr; struct provider *next; }; +/* + * Handling of multiple forms of packaging: + * + * - category is a keyword that identifies the packaging type, e.g., + * T for tape/tray, MAN for manual feeding, etc. + * - a query can be constrained to a set of categories + * - conversion options (e.g., "Digi-Reel") can be expressed as additional + * entries + * + * @@@ To do: shared availability + */ + struct stock { + const char *cat; /* category */ int avail; /* items in stock */ int package; /* "natural" quantity (reel, tray, bag, etc.) */ - struct price *manual; /* single parts, for manual assembly only */ - double reeling; /* cost of converting "manual" to "fab"; <0 if n/a */ - struct price *fab; /* for automated assembly */ + const struct currency *curr; + double add; /* additive element of cost */ + struct price *price; } stock; struct part { @@ -66,6 +95,7 @@ struct part *part_lookup(const char *domain, const char *name); struct part *part_add(const char *domain, const char *name); void part_alias(struct part *a, struct part *b); void part_finalize(struct part *part, const struct action *act); +void part_add_stock(struct part *part, struct stock *stock); void part_dump(FILE *file, const struct part *part); #endif /* !DB_H */ diff --git a/b2/lang.h b/b2/lang.h index da060af..ae61fca 100644 --- a/b2/lang.h +++ b/b2/lang.h @@ -15,6 +15,7 @@ void parse_hierarchy(void); void parse_characteristics(void); +void parse_inventory(void); void yywarnf(const char *fmt, ...); void yyerrorf(const char *fmt, ...); diff --git a/b2/lang.l b/b2/lang.l index 99b5a4c..ac27462 100644 --- a/b2/lang.l +++ b/b2/lang.l @@ -44,6 +44,15 @@ void parse_characteristics(void) yyparse(); } + +void parse_inventory(void) +{ + start_token = START_INVENTORY; + expose_nl = 1; + lineno = 1; + yyparse(); +} + %} diff --git a/b2/lang.y b/b2/lang.y index 7f39cc1..0c0f894 100644 --- a/b2/lang.y +++ b/b2/lang.y @@ -64,6 +64,8 @@ static const struct field *top_field(void) %union { const char *s; + int num; + double fnum; struct equiv *equiv; struct names *names; struct format *format; @@ -74,13 +76,17 @@ static const struct field *top_field(void) struct action act; struct part *part; struct param *param; + struct price *price; + struct stock *stock; }; -%token START_HIERARCHY START_CHAR +%token START_HIERARCHY START_CHAR START_INVENTORY %token TOK_LE TOK_GE TOK_NL %token WORD +%type int +%type float %type nameqs %type names nameq %type format @@ -89,16 +95,23 @@ static const struct field *top_field(void) %type selectors %type conditions condition %type opt_wildcard action -%type part +%type part inventory_item %type param params +%type prices price +%type stock %% all: START_HIERARCHY hierarchy | START_CHAR characteristics + | START_INVENTORY inventory ; + +/* ----- Characteristics hierarchy ----------------------------------------- */ + + hierarchy: nameset hierarchy | action @@ -349,6 +362,10 @@ format: } ; + +/* ----- Part characteristics --------------------------------------------- */ + + characteristics: | TOK_NL | part characteristics @@ -389,3 +406,79 @@ param: $$->value.u.name = $3; } ; + + +/* ----- Part inventory ---------------------------------------------------- */ + + +inventory: + | TOK_NL + | inventory_item inventory + ; + +inventory_item: + WORD WORD stock TOK_NL + { + $$ = part_lookup($1, $2); + if (!$$) + $$ = part_add($1, $2); + part_add_stock($$, $3); + } + ; + +stock: + WORD int int WORD float prices + { + $$ = alloc_type(struct stock); + $$->cat = $1; + $$->avail = $2; + $$->package = $3; + $$->curr = NULL; /* @@@ later -- currency($4); */ + $$->add = $5; + $$->price = $6; + } + ; + +prices: + price + { + $$ = $1; + } + | price prices + { + $$ = $1; + $$->next = $2; + } + ; + +price: + int float + { + $$ = alloc_type(struct price); + $$->qty = $1; + $$->value = $2; + $$->next = NULL; + } + ; + +int: + WORD + { + char *end; + + $$ = strtol($1, &end, 10); + if (*end) + yyerrorf("\"%s\" is not an integer", $1); + } + ; + +float: + WORD + { + char *end; + + $$ = strtod($1, &end); + if (*end) + yyerrorf("\"%s\" is not a number", $1); + } + ;