finish normal user;

check out finish;
enhance ui;
fix bugs
This commit is contained in:
stmctommyau 2022-09-03 22:16:20 +08:00
parent baeef3f7c8
commit e8fb9616f3
10 changed files with 316 additions and 68 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@ main.exe
.VSCodeCounter/*
.vscode/*
.vscode/settings.json
data_file_transaction.txt

View File

@ -6,6 +6,8 @@
#include<string.h>
#include<stdbool.h>
#include<math.h>
#include<time.h>
#include<ctype.h>
#endif
#ifndef MENU_H

4
data_file_admin.txt Normal file
View File

@ -0,0 +1,4 @@
#name of role that are consider as admin
Teacher
Staff
Admin

View File

@ -6,6 +6,8 @@
#include<string.h>
#include<stdbool.h>
#include<math.h>
#include<time.h>
#include<ctype.h>
#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;i<invt->db.row_count;i++){
if(invt->row[i].isdeleted == true){
for(int i=0;i<invt.db.row_count;i++){
if(invt.row[i].isdeleted == true){
continue;
}
for(INVENTORY j=category;j<ENDOFINVENTORY;j++){
for(INVENTORY j=category;j<=ENDOFINVENTORY;j++){
char buffer[100];
do{
if(feof(fpR)){
@ -279,22 +315,22 @@ bool update_db_invt(struct inventory* invt){
}while(buffer[0] == '#');
switch(j){
case category:
fprintf(fpW,"%s",invt->row[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;i<tran->db.row_count;i++){
if(tran->row[i].isdeleted == true){
for(int i=0;i<tran.db.row_count;i++){
if(tran.row[i].isdeleted == true){
continue;
}
for(TRANSACTION j=date;j<ENDOFTRANSACTION;j++){
for(TRANSACTION j=date;j<=ENDOFTRANSACTION;j++){
char buffer[100];
do{
if(feof(fpR)){
@ -335,22 +371,22 @@ bool update_db_tran(struct transaction* tran){
}while(buffer[0] == '#');
switch(j){
case date:
fprintf(fpW,"%d-%d-%d",tran->row[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;i<user->db.row_count;i++){
if(user->row[i].isdeleted == true){
for(int i=0;i<user.db.row_count;i++){
if(user.row[i].isdeleted == true){
continue;
}
for(USER j=name;j<ENDOFUSER;j++){
for(USER j=name;j<=ENDOFUSER;j++){
char buffer[100];
do{
if(feof(fpR)){
@ -390,13 +426,13 @@ bool update_db_user(struct user* user){
}while(buffer[0] == '#');
switch(j){
case name:
fprintf(fpW,"%s",user->row[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;i<invt.db.row_count;i++){
if(invt.row[i].barcode == temp->row->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;i<row_count;i++){
for(USER j=name;j<=ENDOFUSER;j++){
char buffer[100];
fgets(buffer, sizeof(buffer),fp);
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(user->name,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;
}

View File

@ -6,17 +6,19 @@
#include<string.h>
#include<stdbool.h>
#include<math.h>
#include<time.h>
#include<ctype.h>
#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;
}

View File

@ -6,4 +6,6 @@
#include<string.h>
#include<stdbool.h>
#include<math.h>
#include<time.h>
#include<ctype.h>
#endif

2
main.c
View File

@ -6,6 +6,8 @@
#include<string.h>
#include<stdbool.h>
#include<math.h>
#include<time.h>
#include<ctype.h>
#endif
#ifndef CUSTOM_H
#define CUSTOM_H

2
menu.h
View File

@ -6,6 +6,8 @@
#include<string.h>
#include<stdbool.h>
#include<math.h>
#include<time.h>
#include<ctype.h>
#endif

View File

@ -6,6 +6,8 @@
#include<string.h>
#include<stdbool.h>
#include<math.h>
#include<time.h>
#include<ctype.h>
#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;
}

View File

@ -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;