Impelemented REFUND command
[tpg/opendispense2.git] / src / server / dispense.c
1 /**
2  */
3 #include "common.h"
4 #include <stdlib.h>
5 #include <limits.h>
6 #include <string.h>
7
8  int    _GetMinBalance(int Account);
9  int    _CanTransfer(int Source, int Destination, int Ammount);
10  int    _Transfer(int Source, int Destination, int Ammount, const char *Reason);
11
12 // === CODE ===
13 /**
14  * \brief Dispense an item for a user
15  * 
16  * The core of the dispense system, I kinda like it :)
17  */
18 int DispenseItem(int ActualUser, int User, tItem *Item)
19 {
20          int    ret, salesAcct;
21         tHandler        *handler;
22         char    *username, *actualUsername;
23         
24         salesAcct = Bank_GetAcctByName(COKEBANK_SALES_ACCT);
25
26         // Check if the user can afford it
27         if( Item->Price && !_CanTransfer(User, salesAcct, Item->Price) )
28         {
29                 return 2;       // 2: No balance
30         }
31         
32         handler = Item->Handler;
33         
34         // Check if the dispense is possible
35         if( handler->CanDispense ) {
36                 ret = handler->CanDispense( User, Item->ID );
37                 if(ret) return 1;       // 1: Unable to dispense
38         }
39         
40         // Get username for debugging
41         username = Bank_GetAcctName(User);
42         
43         // Actually do the dispense
44         if( handler->DoDispense ) {
45                 ret = handler->DoDispense( User, Item->ID );
46                 if(ret) {
47                         Log_Error("Dispense failed (%s dispensing '%s' - %ic)",
48                                 username, Item->Name, Item->Price);
49                         free( username );
50                         return -1;      // 1: Unknown Error again
51                 }
52         }
53         
54         // Take away money
55         if( Item->Price )
56         {
57                 char    *reason;
58                 reason = mkstr("Dispense - %s:%i %s", handler->Name, Item->ID, Item->Name);
59                 _Transfer( User, salesAcct, Item->Price, reason );
60                 free(reason);
61         }
62         
63         actualUsername = Bank_GetAcctName(ActualUser);
64         
65         // And log that it happened
66         Log_Info("dispense '%s' (%s:%i) for %s by %s [cost %i, balance %i]",
67                 Item->Name, handler->Name, Item->ID,
68                 username, actualUsername, Item->Price, Bank_GetBalance(User)
69                 );
70         
71         free( username );
72         free( actualUsername );
73         return 0;       // 0: EOK
74 }
75
76 /**
77  * \brief Refund a dispense
78  */
79 int DispenseRefund(int ActualUser, int DestUser, tItem *Item, int OverridePrice)
80 {
81          int    ret;
82          int    src_acct, price;
83         char    *username, *actualUsername;
84
85         src_acct = Bank_GetAcctByName(COKEBANK_SALES_ACCT);
86
87         if( OverridePrice > 0 )
88                 price = OverridePrice;
89         else
90                 price = Item->Price;
91
92         ret = _Transfer( src_acct, DestUser, price, "Refund");
93         if(ret) return ret;
94
95         username = Bank_GetAcctName(DestUser);
96         actualUsername = Bank_GetAcctName(ActualUser);
97         
98         Log_Info("refund '%s' (%s:%i) to %s by %s [cost %i, balance %i]",
99                 Item->Name, Item->Handler->Name, Item->ID,
100                 username, actualUsername, price, Bank_GetBalance(DestUser)
101                 );
102
103         free(username);
104         free(actualUsername);
105
106         return 0;
107 }
108
109 /**
110  * \brief Give money from one user to another
111  */
112 int DispenseGive(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven)
113 {
114          int    ret;
115         char    *actualUsername;
116         char    *srcName, *dstName;
117         
118         if( Ammount < 0 )       return 1;       // Um... negative give? Not on my watch!
119         
120         ret = _Transfer( SrcUser, DestUser, Ammount, ReasonGiven );
121         if(ret) return 2;       // No Balance
122         
123         
124         actualUsername = Bank_GetAcctName(ActualUser);
125         srcName = Bank_GetAcctName(SrcUser);
126         dstName = Bank_GetAcctName(DestUser);
127         
128         Log_Info("give %i to %s from %s by %s [balances %i, %i] - %s",
129                 Ammount, dstName, srcName, actualUsername,
130                 Bank_GetBalance(SrcUser), Bank_GetBalance(DestUser),
131                 ReasonGiven
132                 );
133         
134         free(srcName);
135         free(dstName);
136         free(actualUsername);
137         
138         return 0;
139 }
140
141 /**
142  * \brief Move money from one user to another (Admin Only)
143  */
144 int DispenseTransfer(int ActualUser, int SrcUser, int DestUser, int Ammount, const char *ReasonGiven)
145 {
146          int    ret;
147         char    *actualUsername;
148         char    *srcName, *dstName;
149
150         // Make sure the user is an admin
151         if( !(Bank_GetFlags(ActualUser) & USER_FLAG_ADMIN) )
152                 return 1;
153         
154         ret = _Transfer( SrcUser, DestUser, Ammount, ReasonGiven );
155         if(ret) return 2;       // No Balance
156         
157         
158         actualUsername = Bank_GetAcctName(ActualUser);
159         srcName = Bank_GetAcctName(SrcUser);
160         dstName = Bank_GetAcctName(DestUser);
161         
162         Log_Info("move %i to %s from %s by %s [balances %i, %i] - %s",
163                 Ammount, dstName, srcName, actualUsername,
164                 Bank_GetBalance(SrcUser), Bank_GetBalance(DestUser),
165                 ReasonGiven
166                 );
167         
168         free(srcName);
169         free(dstName);
170         free(actualUsername);
171         
172         return 0;
173 }
174 /**
175  * \brief Add money to an account
176  */
177 int DispenseAdd(int ActualUser, int User, int Ammount, const char *ReasonGiven)
178 {
179          int    ret;
180         char    *dstName, *byName;
181         
182 #if DISPENSE_ADD_BELOW_MIN
183         ret = _Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Ammount, ReasonGiven );
184 #else
185         ret = Bank_Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Ammount, ReasonGiven );
186 #endif
187         if(ret) return 2;
188         
189         byName = Bank_GetAcctName(ActualUser);
190         dstName = Bank_GetAcctName(User);
191         
192         Log_Info("add %i to %s by %s [balance %i] - %s",
193                 Ammount, dstName, byName, Bank_GetBalance(User), ReasonGiven
194                 );
195         
196         free(byName);
197         free(dstName);
198         
199         return 0;
200 }
201
202 int DispenseSet(int ActualUser, int User, int Balance, const char *ReasonGiven)
203 {
204          int    curBal = Bank_GetBalance(User);
205         char    *byName, *dstName;
206         
207         _Transfer( Bank_GetAcctByName(COKEBANK_DEBT_ACCT), User, Balance-curBal, ReasonGiven );
208         
209         byName = Bank_GetAcctName(ActualUser);
210         dstName = Bank_GetAcctName(User);
211         
212         Log_Info("set balance of %s to %i by %s [balance %i] - %s",
213                 dstName, Balance, byName, Bank_GetBalance(User), ReasonGiven
214                 );
215         
216         free(byName);
217         free(dstName);
218         
219         return 0;
220 }
221
222 /**
223  * \brief Donate money to the club
224  */
225 int DispenseDonate(int ActualUser, int User, int Ammount, const char *ReasonGiven)
226 {
227          int    ret;
228         char    *srcName, *byName;
229         
230         if( Ammount < 0 )       return 2;
231         
232         ret = _Transfer( User, Bank_GetAcctByName(COKEBANK_DEBT_ACCT), Ammount, ReasonGiven );
233         if(ret) return 2;
234         
235         byName = Bank_GetAcctName(ActualUser);
236         srcName = Bank_GetAcctName(User);
237         
238         Log_Info("donate %i from %s by %s [balance %i] - %s",
239                 Ammount, srcName, byName, Bank_GetBalance(User), ReasonGiven
240                 );
241         
242         free(byName);
243         free(srcName);
244         
245         return 0;
246 }
247
248 // --- Internal Functions ---
249 int _GetMinBalance(int Account)
250 {
251          int    flags = Bank_GetFlags(Account);
252         
253         // Evil little piece of HACK:
254         // root's balance cannot be changed by any of the above functions
255         // - Stops dispenses as root by returning insufficent balance.
256         {
257                 char    *username = Bank_GetAcctName(Account);
258                 if( strcmp(username, "root") == 0 )
259                 {
260                         free(username);
261                         return INT_MAX;
262                 }
263                 free(username);
264         }
265         
266         // - Internal accounts have no lower bound
267         if( flags & USER_FLAG_INTERNAL )        return INT_MIN;
268         
269         // Admin to -$50
270 //      if( flags & USER_FLAG_ADMIN )   return -5000;
271         
272         // Coke to -$20
273 //      if( flags & USER_FLAG_COKE )    return -2000;
274         
275         // Anyone else, non-negative
276         return 0;
277 }
278
279 /**
280  * \brief Check if a transfer is possible
281  */
282 int _CanTransfer(int Source, int Destination, int Ammount)
283 {
284         if( Ammount > 0 )
285         {
286                 if( Bank_GetBalance(Source) - Ammount < _GetMinBalance(Source) )
287                         return 0;
288         }
289         else
290         {
291                 if( Bank_GetBalance(Destination) + Ammount < _GetMinBalance(Destination) )
292                         return 0;
293         }
294         return 1;
295 }
296
297 int _Transfer(int Source, int Destination, int Ammount, const char *Reason)
298 {
299         if( !_CanTransfer(Source, Destination, Ammount) )
300                 return 1;
301         return Bank_Transfer(Source, Destination, Ammount, Reason);
302 }

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