SQLite database works, time for more thorough stress testing
[tpg/opendispense2.git] / src / server / dispense.c
1 /**
2  */
3 #include "common.h"
4 #include <stdlib.h>
5 #include <limits.h>
6
7  int    _GetMinBalance(int Account);
8  int    _Transfer(int Source, int Destination, int Ammount, const char *Reason);
9
10 // === CODE ===
11 /**
12  * \brief Dispense an item for a user
13  * 
14  * The core of the dispense system, I kinda like it :)
15  */
16 int DispenseItem(int ActualUser, int User, tItem *Item)
17 {
18          int    ret;
19         tHandler        *handler;
20         char    *username, *actualUsername;
21         char    *reason;
22         
23         handler = Item->Handler;
24         
25         // Check if the dispense is possible
26         if( handler->CanDispense ) {
27                 ret = handler->CanDispense( User, Item->ID );
28                 if(ret) return 1;       // 1: Unable to dispense
29         }
30
31         // Subtract the balance
32         reason = mkstr("Dispense - %s:%i %s", handler->Name, Item->ID, Item->Name);
33         if( !reason )   reason = Item->Name;    // TODO: Should I instead return an error?
34         ret = _Transfer( User, Bank_GetAcctByName(COKEBANK_SALES_ACCT), Item->Price, reason);
35         free(reason);
36         if(ret) return 2;       // 2: No balance
37         
38         // Get username for debugging
39         username = Bank_GetAcctName(User);
40         
41         // Actually do the dispense
42         if( handler->DoDispense ) {
43                 ret = handler->DoDispense( User, Item->ID );
44                 if(ret) {
45                         Log_Error("Dispense failed after deducting cost (%s dispensing %s - %ic)",
46                                 username, Item->Name, Item->Price);
47                         _Transfer( Bank_GetAcctByName(COKEBANK_SALES_ACCT), User, Item->Price, "rollback" );
48                         free( username );
49                         return -1;      // 1: Unkown Error again
50                 }
51         }
52         
53         actualUsername = Bank_GetAcctName(ActualUser);
54         
55         // And log that it happened
56         Log_Info("dispense '%s' (%s:%i) for %s by %s [cost %i, balance %i]",
57                 Item->Name, handler->Name, Item->ID,
58                 username, actualUsername, Item->Price, Bank_GetBalance(User)
59                 );
60         
61         free( username );
62         free( actualUsername );
63         return 0;       // 0: EOK
64 }
65
66 /**
67  * \brief Give money from one user to another
68  */
69 int DispenseGive(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven)
70 {
71          int    ret;
72         char    *actualUsername;
73         char    *srcName, *dstName;
74         
75         if( Ammount < 0 )       return 1;       // Um... negative give? Not on my watch!
76         
77         ret = _Transfer( SrcUser, DestUser, Ammount, ReasonGiven );
78         if(ret) return 2;       // No Balance
79         
80         
81         actualUsername = Bank_GetAcctName(ActualUser);
82         srcName = Bank_GetAcctName(SrcUser);
83         dstName = Bank_GetAcctName(DestUser);
84         
85         Log_Info("give %i to %s from %s by %s [balances %i, %i] - %s",
86                 Ammount, dstName, srcName, actualUsername,
87                 Bank_GetBalance(SrcUser), Bank_GetBalance(DestUser),
88                 ReasonGiven
89                 );
90         
91         free(srcName);
92         free(dstName);
93         free(actualUsername);
94         
95         return 0;
96 }
97
98 /**
99  * \brief Add money to an account
100  */
101 int DispenseAdd(int ActualUser, int User, int Ammount, const char *ReasonGiven)
102 {
103          int    ret;
104         char    *dstName, *byName;
105         
106         ret = _Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Ammount, ReasonGiven );
107         if(ret) return 2;
108         
109         byName = Bank_GetAcctName(ActualUser);
110         dstName = Bank_GetAcctName(User);
111         
112         Log_Info("add %i to %s by %s [balance %i] - %s",
113                 Ammount, dstName, byName, Bank_GetBalance(User), ReasonGiven
114                 );
115         
116         free(byName);
117         free(dstName);
118         
119         return 0;
120 }
121
122 /**
123  * \brief Donate money to the club
124  */
125 int DispenseDonate(int ActualUser, int User, int Ammount, const char *ReasonGiven)
126 {
127          int    ret;
128         char    *srcName, *byName;
129         
130         if( Ammount < 0 )       return 2;
131         
132         ret = _Transfer( User, Bank_GetAcctByName(COKEBANK_DEBT_ACCT), Ammount, ReasonGiven );
133         if(ret) return 2;
134         
135         byName = Bank_GetAcctName(ActualUser);
136         srcName = Bank_GetAcctName(User);
137         
138         Log_Info("donate %i from %s by %s [balance %i] - %s",
139                 Ammount, srcName, byName, Bank_GetBalance(User), ReasonGiven
140                 );
141         
142         free(byName);
143         free(srcName);
144         
145         return 0;
146 }
147
148 // --- Internal Functions ---
149 int _GetMinBalance(int Account)
150 {
151          int    flags = Bank_GetFlags(Account);
152         
153         // - Internal accounts have no lower bound
154         if( flags & USER_FLAG_INTERNAL )        return INT_MIN;
155         
156         // Admin to -$10
157         if( flags & USER_FLAG_ADMIN )   return -1000;
158         
159         // Coke to -$10
160         if( flags & USER_FLAG_COKE )    return -500;
161         
162         // Anyone else, non-negative
163         return 0;
164 }
165
166 int _Transfer(int Source, int Destination, int Ammount, const char *Reason)
167 {
168         if( Ammount > 0 )
169         {
170                 if( Bank_GetBalance(Source) + Ammount < _GetMinBalance(Source) )
171                         return 1;
172         }
173         else
174         {
175                 if( Bank_GetBalance(Destination) - Ammount < _GetMinBalance(Destination) )
176                         return 1;
177         }
178         
179         return Bank_Transfer(Source, Destination, Ammount, Reason);
180 }

UCC git Repository :: git.ucc.asn.au