From e8fb9616f39a877477d76d76b8dcfdc88c690341 Mon Sep 17 00:00:00 2001 From: stmctommyau Date: Sat, 3 Sep 2022 22:16:20 +0800 Subject: [PATCH] finish normal user; check out finish; enhance ui; fix bugs --- .gitignore | 2 + admin_user.h | 2 + data_file_admin.txt | 4 + database.h | 228 ++++++++++++++++++++++++++++++++++++-------- dateNtime.h | 42 ++++++-- filecontrol.h | 2 + main.c | 2 + menu.h | 2 + normal_user.h | 98 +++++++++++++++---- sorting.h | 2 +- 10 files changed, 316 insertions(+), 68 deletions(-) create mode 100644 data_file_admin.txt diff --git a/.gitignore b/.gitignore index 2d207c8..3fcd254 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ main.exe .VSCodeCounter/* .vscode/* .vscode/settings.json +data_file_transaction.txt + diff --git a/admin_user.h b/admin_user.h index 5b47756..6f2f496 100644 --- a/admin_user.h +++ b/admin_user.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #endif #ifndef MENU_H diff --git a/data_file_admin.txt b/data_file_admin.txt new file mode 100644 index 0000000..2f31a47 --- /dev/null +++ b/data_file_admin.txt @@ -0,0 +1,4 @@ +#name of role that are consider as admin +Teacher +Staff +Admin \ No newline at end of file diff --git a/database.h b/database.h index 682b7f8..294c5cc 100644 --- a/database.h +++ b/database.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #endif #ifndef DNT_H #define DNT_H @@ -15,7 +17,7 @@ typedef struct basic_db{ int row_count; bool init_status; //array of struct of row -}; +}basic_db; //inventory #define INVENTORY_DB "data_file_inventory.txt" @@ -23,7 +25,7 @@ typedef struct inventory{ struct basic_db db; struct inventory_row* row; -}; +}inventory; typedef struct inventory_row{ char category[100]; char brand[100]; @@ -32,7 +34,7 @@ typedef struct inventory_row{ int stock; long barcode; bool isdeleted;//common for all rows,default is false -}; +}inventory_row; typedef enum { category = 1, brand = 2, product = 3, price_inv = 4, stock = 5, barcode_inv = 6 }INVENTORY; @@ -43,18 +45,18 @@ typedef struct transaction{ struct basic_db db; struct transaction_row* row; -}; +}transaction; typedef struct transaction_row{ - struct date date; - struct time time; + struct Date date; + struct Time time; long id; double price; int quantity; long barcode; bool isdeleted;//common for all rows,default is false -}; +}transaction_row; typedef enum { - date = 1, time = 2, id_tran = 3, price_tran = 4, quantity = 5, barcode_tran = 6 + date = 1, TIME = 2, id_tran = 3, price_tran = 4, quantity = 5, barcode_tran = 6 }TRANSACTION; #define ENDOFTRANSACTION 6 //user @@ -62,21 +64,45 @@ typedef enum { typedef struct user{ struct basic_db db; struct user_row* row; -}; +}user; typedef struct user_row{ char name[100]; char role[100]; long id; bool isAdmin; bool isdeleted;//common for all rows,default is false -}; +}user_row; typedef enum { name = 1, role = 2, id_user = 3 }USER; #define ENDOFUSER 3 +//admin verify +#define ADMIN_DB "data_file_admin.txt" +//func for admin verify +bool is_admin(char* role){ + FILE* fp = fopen(ADMIN_DB,"r"); + if(fp == NULL){ + printf("Error opening file\n"); + return false; + } + char line[100]; + while(fgets(line,100,fp) != NULL){ + if(line[0] == '#') continue; + + if(line[strlen(line)-1] == '\n') + line[strlen(line)-1] = '\0'; + + if(strcmp(line,role) == 0){ + fclose(fp); + return true; + } + } + fclose(fp); + return false; +} //list of db func int basic_get_row_count(int end, FILE *fp){ @@ -119,6 +145,10 @@ struct inventory read_db_invt(){//please open file in read mode if(buffer[0] == '#'){//catch comment line and ignore j--;//decrement j to prevent skipping next column }else{ + + if(buffer[strlen(buffer)-1] == '\n') + buffer[strlen(buffer)-1] = '\0'; + switch(j){ case category: strcpy(db.row[i].category,buffer); @@ -175,11 +205,14 @@ struct transaction read_db_tran(){ if(buffer[0] == '#'){//catch comment line and ignore j--;//decrement j to prevent skipping next column }else{ + if(buffer[strlen(buffer)-1] == '\n') + buffer[strlen(buffer)-1] = '\0'; + switch(j){ case date: db.row[i].date = convert_to_date(buffer); break; - case time: + case TIME: db.row[i].time = convert_to_time(buffer); break; case id_tran: @@ -228,6 +261,9 @@ struct user read_db_user(){ if(buffer[0] == '#'){//catch comment line and ignore j--;//decrement j to prevent skipping next column }else{ + if(buffer[strlen(buffer)-1] == '\n') + buffer[strlen(buffer)-1] = '\0'; + switch(j){ case name: strcpy(db.row[i].name,buffer); @@ -253,7 +289,7 @@ struct user read_db_user(){ return db; } -bool update_db_invt(struct inventory* invt){ +bool update_db_invt(struct inventory invt){ FILE* fpR = fopen(INVENTORY_DB,"r"); char temp[30] = INVENTORY_DB; strcat(temp,".temp"); @@ -262,11 +298,11 @@ bool update_db_invt(struct inventory* invt){ printf("Error in opening file\n"); return false; } - for(int i=0;idb.row_count;i++){ - if(invt->row[i].isdeleted == true){ + for(int i=0;irow[i].category); + fprintf(fpW,"%s",invt.row[i].category); break; case brand: - fprintf(fpW,"%s",invt->row[i].brand); + fprintf(fpW,"%s",invt.row[i].brand); break; case product: - fprintf(fpW,"%s",invt->row[i].product); + fprintf(fpW,"%s",invt.row[i].product); break; case price_inv: - fprintf(fpW,"%f",invt->row[i].price); + fprintf(fpW,"%.1f",invt.row[i].price); break; case stock: - fprintf(fpW,"%d",invt->row[i].stock); + fprintf(fpW,"%d",invt.row[i].stock); break; case barcode_inv: - fprintf(fpW,"%ld",invt->row[i].barcode); + fprintf(fpW,"%ld",invt.row[i].barcode); break; } fprintf(fpW,"\n"); @@ -309,7 +345,7 @@ bool update_db_invt(struct inventory* invt){ } -bool update_db_tran(struct transaction* tran){ +bool update_db_tran(struct transaction tran){ FILE* fpR = fopen(TRANSACTION_DB,"r"); char temp[30] = TRANSACTION_DB; strcat(temp,".temp"); @@ -318,11 +354,11 @@ bool update_db_tran(struct transaction* tran){ printf("Error in opening file\n"); return false; } - for(int i=0;idb.row_count;i++){ - if(tran->row[i].isdeleted == true){ + for(int i=0;irow[i].date.day,tran->row[i].date.month,tran->row[i].date.year); + fprintf(fpW,"%d-%02d-%02d",tran.row[i].date.year,tran.row[i].date.month,tran.row[i].date.day); break; - case time: - fprintf(fpW,"%d:%d:%d",tran->row[i].time.hour,tran->row[i].time.minute,tran->row[i].time.second); + case TIME: + fprintf(fpW,"%02d:%02d:%02d",tran.row[i].time.hour,tran.row[i].time.minute,tran.row[i].time.second); break; case id_tran: - fprintf(fpW,"%ld",tran->row[i].id); + fprintf(fpW,"%ld",tran.row[i].id); break; case price_tran: - fprintf(fpW,"%f",tran->row[i].price); + fprintf(fpW,"%.1f",tran.row[i].price); break; case quantity: - fprintf(fpW,"%d",tran->row[i].quantity); + fprintf(fpW,"%d",tran.row[i].quantity); break; case barcode_tran: - fprintf(fpW,"%ld",tran->row[i].barcode); + fprintf(fpW,"%ld",tran.row[i].barcode); break; } fprintf(fpW,"\n"); @@ -364,7 +400,7 @@ bool update_db_tran(struct transaction* tran){ return true; } -bool update_db_user(struct user* user){ +bool update_db_user(struct user user){ FILE* fpR = fopen(USER_DB,"r"); char temp[30] = USER_DB; strcat(temp,".temp"); @@ -373,11 +409,11 @@ bool update_db_user(struct user* user){ printf("Error in opening file\n"); return false; } - for(int i=0;idb.row_count;i++){ - if(user->row[i].isdeleted == true){ + for(int i=0;irow[i].name); + fprintf(fpW,"%s",user.row[i].name); break; case role: - fprintf(fpW,"%s",user->row[i].role); + fprintf(fpW,"%s",user.row[i].role); break; case id_user: - fprintf(fpW,"%ld",user->row[i].id); + fprintf(fpW,"%ld",user.row[i].id); break; } fprintf(fpW,"\n"); @@ -408,4 +444,118 @@ bool update_db_user(struct user* user){ remove(USER_DB); rename(temp,USER_DB); return true; +} + +//checkout db support, + +typedef struct cart{//linked list + struct inventory_row* row;//pointer to the row + int quantity;//quantity of the item + struct cart* next; +}cart; + + +bool append_transaction(struct cart* cart,struct user_row* user){ + FILE* fp = fopen(TRANSACTION_DB,"a"); + if(fp == NULL){ + printf("Error in opening file\n"); + return false; + } + + struct Date date = get_date(); + struct Time time = get_time(); + struct cart* temp = cart; + if(temp == NULL) + return false; + + do{ + + fprintf(fp,"%d-%02d-%02d\n",date.year,date.month,date.day); + fprintf(fp,"%02d:%02d:%02d\n",time.hour,time.minute,time.second); + fprintf(fp,"%ld\n",user->id); + fprintf(fp,"%f\n",temp->row->price); + fprintf(fp,"%d\n",temp->quantity); + fprintf(fp,"%ld\n",temp->row->barcode); + if(temp->next == NULL) + break; + temp = temp->next; + }while(temp->next != NULL);//this while condition just for safety,as it should already break in the if statement + fclose(fp); + return true; +} + +bool update_stock_N_checkout(struct cart* cart,struct user_row* user){ + struct inventory invt = read_db_invt(); + struct cart* temp = cart; + if(temp == NULL) + return false; + do{ + for(int i=0;irow->barcode){ + invt.row[i].stock -= temp->quantity; + break; + } + } + if(temp->next == NULL) + break; + temp = temp->next; + }while(temp->next != NULL);//this while condition just for safety,as it should already break in the if statement + if(!append_transaction(cart,user)){ + return false; + } + if(!update_db_invt(invt)){ + return false; + } + return true; +} + +//user +struct user_row* get_user(long userid){ + struct user_row* user = (struct user_row*)malloc(sizeof(struct user_row)); + FILE* fp = fopen(USER_DB,"r"); + if(fp == NULL){ + printf("Error in opening file\n"); + return NULL; + } + char buffer[100]; + + //gets the number of rows in the file + int row_count = basic_get_row_count(ENDOFUSER,fp); + + fseek(fp,0,SEEK_SET);//reset fp to the beginning of the file + + //read data + for(int i=0;iname,buffer); + break; + case role: + strcpy(user->role,buffer); + break; + case id_user: + user->id = atol(buffer); + if(user->id == userid){ + fclose(fp); + return user; + } + break; + } + } + + } + } + fclose(fp); + return NULL; } \ No newline at end of file diff --git a/dateNtime.h b/dateNtime.h index a97a04c..f7712b3 100644 --- a/dateNtime.h +++ b/dateNtime.h @@ -6,17 +6,19 @@ #include #include #include +#include +#include #endif //DATE -typedef struct date{ +typedef struct Date{ int day; int month; int year; -}; +}Date; -struct date convert_to_date(char* date){ - struct date d; +struct Date convert_to_date(char* date){ + struct Date d; char* token = strtok(date, "-"); d.day = atoi(token); token = strtok(NULL, "-"); @@ -26,16 +28,28 @@ struct date convert_to_date(char* date){ return d; } +struct Date get_date(){ + struct Date d; + time_t rawtime; + struct tm * timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + d.day = timeinfo->tm_mday; + d.month = timeinfo->tm_mon + 1; + d.year = timeinfo->tm_year + 1900; + return d; +} + //TIME -typedef struct time{ +typedef struct Time{ int hour; int minute; int second; -}; +}Time; -struct time convert_to_time(char* time){ - struct time t; +struct Time convert_to_time(char* time){ + struct Time t; char* token = strtok(time, ":"); t.hour = atoi(token); token = strtok(NULL, ":"); @@ -43,4 +57,16 @@ struct time convert_to_time(char* time){ token = strtok(NULL, ":"); t.second = atoi(token); return t; +} + +struct Time get_time(){ + struct Time t; + time_t rawtime; + struct tm * timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + t.hour = timeinfo->tm_hour; + t.minute = timeinfo->tm_min; + t.second = timeinfo->tm_sec; + return t; } \ No newline at end of file diff --git a/filecontrol.h b/filecontrol.h index d6f5644..186bd61 100644 --- a/filecontrol.h +++ b/filecontrol.h @@ -6,4 +6,6 @@ #include #include #include +#include +#include #endif diff --git a/main.c b/main.c index ead9514..27ddceb 100644 --- a/main.c +++ b/main.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #endif #ifndef CUSTOM_H #define CUSTOM_H diff --git a/menu.h b/menu.h index 5ad1d9b..2424ba4 100644 --- a/menu.h +++ b/menu.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #endif diff --git a/normal_user.h b/normal_user.h index cb0dacc..fc15157 100644 --- a/normal_user.h +++ b/normal_user.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #endif #ifndef MENU_H @@ -62,7 +64,7 @@ void show_item(struct inventory db,int index){ system("cls"); printf("Product: %s\n", db.row[index].product); printf("Catergory: %s\n", db.row[index].category); - printf("Brand: %d\n", db.row[index].brand); + printf("Brand: %s\n", db.row[index].brand); printf("Price: $%lf\n", db.row[index].price); printf("Stock: %d\n", db.row[index].stock); printf("Barcode: %ld\n",db.row[index].barcode); @@ -97,8 +99,8 @@ void list_page(struct inventory db,struct Map* map,int row){//user for showing l printf("2 sort name ascending\n"); printf("3 sort price decending\n"); printf("4 sort price ascending\n"); - printf("5 sort band decending\n"); - printf("6 sort band ascending\n"); + printf("5 sort brand decending\n"); + printf("6 sort brand ascending\n"); printf("7 sort category decending\n"); printf("8 sort category ascending\n"); printf("List of items:\n"); @@ -119,6 +121,7 @@ void list_page(struct inventory db,struct Map* map,int row){//user for showing l //prompt user to select an item bool valid = true; do{ + valid = true; printf("Enter your choice: "); fflush(stdin); scanf("%d", &choice); @@ -186,7 +189,7 @@ struct Map* sortItems(struct inventory db, int sort){ case 3: case 4: long price = db.row[i].price * 100; - map[i].value = (void*)price;//presume there is no price contain 0.001 + map[i].value = (long*)price;//presume there is no price contain 0.001 break; case 5: case 6: @@ -245,6 +248,7 @@ void search_item(){ if(breakout == 1 || breakout == 0){ valid = true; }else{ + valid = false; printf("Invalid choice\n"); } }while(!valid); @@ -255,7 +259,7 @@ void search_item(){ printf("searching...\n"); map = searchItems(db,searchstr); if(map[0].value > 0){ - list_page(db,map+1,map[0].value);//ofset map, as it is use to store the size + list_page(db,map+1,(int)map[0].value);//ofset map, as it is use to store the size }else{//empty search printf("No result found\n"); printf("Press any key to continue\n"); @@ -310,17 +314,13 @@ struct Map* searchItems(struct inventory db, char* searchstr){ k++; } } - map[0].value = k-1; + map[0].value = (int*)(k-1); map[0].key = -1; return map; } //self help -typedef struct cart{//linked list - struct inventory_row* row;//pointer to the row - int quantity;//quantity of the item - struct cart* next; -}; + int self_choice(); struct cart* scan_barcode(struct cart* cart,struct inventory db); @@ -491,8 +491,15 @@ struct cart* scan_barcode(struct cart* cart,struct inventory db){ getchar(); return cart; } - printf("Are you sure you want to add this item to cart?(y/n)"); + printf("Are you sure you want to add this item to cart?(y/n)\n>"); + fflush(stdin); scanf("%c", &choice); + if(row->stock - quantity < 0 && choice == 'y'){ + printf("WARNING:not enough stock\n"); + printf("Are you sure the quantity is correct?\n(y to ignore and continue/n)\n>"); + fflush(stdin); + scanf("%c", &choice); + } }while(choice != 'y'); if(quantity != 0){ cart = Cartappend(cart,row,quantity); @@ -520,7 +527,6 @@ long prompt_barcode(){ struct inventory_row* find_barcode(struct inventory db,long barcode){ struct inventory_row row; for (int i = 0; i < db.db.row_count; i++){ - printf("%ld\n",db.row[i].barcode); if(db.row[i].barcode == barcode){ return &db.row[i]; @@ -549,16 +555,22 @@ struct cart* list_cart(struct cart* cart){ int qty = temp->quantity; double price = temp->row->price * qty; total_price += price; - printf("%d product:%s price:$%lf\n quantity:%d\n",i,temp->row->product,price,qty); + printf("%d product:%s\n",i,temp->row->product); + printf(" price(per qty): %.2f\n",temp->row->price);//space to align + printf(" price(total): %.2f\n",price); + printf(" quantity: %d\n",qty); printf("<------------------------>\n"); temp = temp->next; i++; } + printf("\n<------------------------>\n"); printf("Total price: $%.2f\n",total_price); - printf("%d checkout\n",i); + printf("<------------------------>\n"); + + printf("\n%d CHECKOUT\n",i); } do{ - printf("input the corrisponding value for more action\n>"); + printf("input the corresponding value for more action\n>"); fflush(stdin); scanf("%d", &choice); if(choice >0 && choice < i){ @@ -642,11 +654,57 @@ struct cart* update_cart(struct cart* cart,int index){ //TODO checkout struct cart* checkout(struct cart* cart){ -//TODO:write db func for transaction -//TODO:write db func for user -//TODO:update stock system("cls"); welcome_message(); - + + long user_id = 0; + printf("Please tap your card(student card, staff card,etc)(or input the id)(0 to cancel)\n>"); + scanf("%ld", &user_id); + if(user_id == 0){ + printf("cancelled\n"); + printf("press any key to continue\n"); + fflush(stdin); + getchar(); + return cart; + } + struct user_row* user = get_user(user_id); + + + if(user == NULL){ + printf("Fail to indentify your card or error occurs\n"); + printf("press any key to continue\n"); + fflush(stdin); + getchar(); + return cart; + }else{ + printf("Welcome %s(%s)\n",user->name,user->role); + printf("Are you sure you want to checkout?(y/n)\n>"); + char choice; + fflush(stdin); + scanf("%c", &choice); + if(choice == 'y'){ + if(update_stock_N_checkout(cart,user)){//catch err + printf("Checkout successful\n"); + printf("press any key to continue\n"); + fflush(stdin); + getchar(); + return NULL; + }else{ + printf("Checkout failed(files maybe corrputed)\n"); + printf("press any key to continue\n"); + fflush(stdin); + getchar(); + return cart; + } + }else{ + printf("cancelled\n"); + printf("press any key to continue\n"); + fflush(stdin); + getchar(); + return cart; + } + } + + return cart; } diff --git a/sorting.h b/sorting.h index 91bc54b..638b127 100644 --- a/sorting.h +++ b/sorting.h @@ -1,7 +1,7 @@ typedef struct Map{ int key; void* value; -}; +}Map; int compare_decending(const void *a, const void *b){ return (*(struct Map *)b).value - (*(struct Map *)a).value;