292 lines
6.7 KiB
C++
292 lines
6.7 KiB
C++
#include "common.h"
|
|
#include "posdb.h"
|
|
#include "log.h"
|
|
#include "sha1.h"
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <ctime>
|
|
|
|
PosDb::PosDb(const char * fn)
|
|
: log(fn)
|
|
{
|
|
// read in the log
|
|
for(std::list<LogEntry>::const_iterator p = log.begin(); p != log.end(); ++p)
|
|
acceptLogEntry(*p);
|
|
}
|
|
|
|
void PosDb::acceptLogEntry(const LogEntry & l) {
|
|
serial_to_object[l.serial] = l;
|
|
switch(l.type) {
|
|
case ET_HASH: {
|
|
SHA1Hash h;
|
|
h.set((unsigned char *)l.HashChange.hash);
|
|
|
|
if(l.HashChange.add) {
|
|
// verify hash not associated with anything
|
|
for(ath_it p = account_to_hash.begin(); p != account_to_hash.end(); ++p) {
|
|
if(p->second == h) {
|
|
fprintf(stderr, "PosDb: Log associates a hash"
|
|
" with more than one account! Aborting.");
|
|
abort();
|
|
}
|
|
}
|
|
account_to_hash.insert(std::pair<uint32_t, SHA1Hash>(l.HashChange.uid, h));
|
|
} else {
|
|
// verify hash associated with something
|
|
ath_it p;
|
|
for(p = account_to_hash.begin(); p != account_to_hash.end(); ++p) {
|
|
if(p->second == h)
|
|
break;
|
|
}
|
|
|
|
if(p == account_to_hash.end()) {
|
|
fprintf(stderr, "PosDb: Log deassociates an"
|
|
"unassociated hash! Aborting.");
|
|
abort();
|
|
} else {
|
|
account_to_hash.erase(p);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ET_TRANS: {
|
|
atb_it q = account_to_balance.find(l.Transaction.uid);
|
|
if(q == account_to_balance.end())
|
|
account_to_balance[l.Transaction.uid] = l.Transaction.delta;
|
|
else
|
|
q->second += l.Transaction.delta;
|
|
break;
|
|
}
|
|
|
|
case ET_SALE: {
|
|
uts_it q = upc_to_stock.find(l.StockChange.upc);
|
|
if(q == upc_to_stock.end())
|
|
upc_to_stock[l.StockChange.upc] = l.StockChange.delta;
|
|
else
|
|
q->second += l.StockChange.delta;
|
|
break;
|
|
}
|
|
|
|
case ET_PRICE: {
|
|
upc_to_price[l.PriceChange.upc] = l.PriceChange.price;
|
|
break;
|
|
}
|
|
|
|
case ET_ADDUPC: {
|
|
upc_to_name[l.AddUPC.upc] = l.AddUPC.name;
|
|
break;
|
|
}
|
|
|
|
case ET_REVERT: {
|
|
sto_it q = serial_to_object.find(l.Revert.revert_serial);
|
|
if((q == serial_to_object.end()) || (q->second.type != ET_TRANS)) {
|
|
fprintf(stderr, "PosDb: Log reverts an invalid object! Aborting.");
|
|
abort();
|
|
} else {
|
|
account_to_balance[q->second.Transaction.uid] -= q->second.Transaction.delta;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
uint32_t PosDb::getAccountFromHash(const SHA1Hash & hash) {
|
|
ath_it p;
|
|
for(p = account_to_hash.begin(); p != account_to_hash.end(); ++p) {
|
|
if(p->second == hash)
|
|
break;
|
|
}
|
|
if(p == account_to_hash.end())
|
|
return 0;
|
|
else
|
|
return p->first;
|
|
}
|
|
|
|
std::list<std::string> PosDb::getHashesFromAccount(uint32_t account) {
|
|
std::list<std::string> result;
|
|
|
|
ath_it_r range = account_to_hash.equal_range(account);
|
|
for(ath_it p = range.first; p != range.second; ++p)
|
|
result.push_back(p->second.toHex());
|
|
|
|
return result;
|
|
}
|
|
|
|
std::list<std::string> PosDb::getHashesFromAccount(std::string account) {
|
|
return getHashesFromAccount(ns.get_id(account));
|
|
}
|
|
|
|
int32_t PosDb::getAccountBalance(const SHA1Hash & hash) {
|
|
uint32_t acct = getAccountFromHash(hash);
|
|
|
|
if(!acct)
|
|
return 0;
|
|
else {
|
|
atb_it p = account_to_balance.find(acct);
|
|
if(p == account_to_balance.end())
|
|
return 0;
|
|
else
|
|
return p->second;
|
|
}
|
|
}
|
|
|
|
int32_t PosDb::getAccountBalance(uint32_t account) {
|
|
atb_it p = account_to_balance.find(account);
|
|
if(p == account_to_balance.end())
|
|
return 0;
|
|
else
|
|
return p->second;
|
|
}
|
|
|
|
int32_t PosDb::getAccountBalance(std::string account) {
|
|
return getAccountBalance(ns.get_id(account));
|
|
}
|
|
|
|
uint64_t PosDb::associateHash(const SHA1Hash & hash, uint32_t account) {
|
|
// verify hash not associated with anything
|
|
if(getAccountFromHash(hash)) {
|
|
return 0;
|
|
} else {
|
|
LogEntry l = log.newLogEntry(ET_HASH);
|
|
l.HashChange.uid = account;
|
|
l.HashChange.add = true;
|
|
hash.get((unsigned char *)l.HashChange.hash);
|
|
|
|
acceptLogEntry(l);
|
|
return log.writeEntry(l);
|
|
}
|
|
}
|
|
|
|
uint64_t PosDb::associateHash(const SHA1Hash & hash, std::string account) {
|
|
return associateHash(hash, ns.get_id(account));
|
|
}
|
|
|
|
uint64_t PosDb::deassociateHash(const SHA1Hash & hash) {
|
|
// verify hash associated with something
|
|
uint32_t acct = getAccountFromHash(hash);
|
|
|
|
if(!acct) {
|
|
return 0;
|
|
} else {
|
|
LogEntry l = log.newLogEntry(ET_HASH);
|
|
l.HashChange.uid = acct;
|
|
l.HashChange.add = false;
|
|
hash.get((unsigned char *)l.HashChange.hash);
|
|
|
|
acceptLogEntry(l);
|
|
return log.writeEntry(l);
|
|
}
|
|
}
|
|
|
|
int32_t PosDb::getUPCPrice(uint64_t upc) {
|
|
uts_it it = upc_to_price.find(upc);
|
|
if (it == upc_to_price.end()) {
|
|
return 0;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
uint64_t PosDb::setUPCPrice(uint64_t upc, int32_t price) {
|
|
LogEntry l = log.newLogEntry(ET_PRICE);
|
|
l.PriceChange.upc = upc;
|
|
l.PriceChange.price = price;
|
|
|
|
acceptLogEntry(l);
|
|
return log.writeEntry(l);
|
|
}
|
|
|
|
// NOTE: this in theory could be deprecated. The client should
|
|
// probably get the uid from the hash before doing a transaction.
|
|
uint64_t PosDb::doTransaction(const SHA1Hash & hash, int32_t delta) {
|
|
// verify hash associated with something
|
|
uint32_t acct = getAccountFromHash(hash);
|
|
|
|
if(!acct) {
|
|
return 0;
|
|
} else {
|
|
LogEntry l = log.newLogEntry(ET_TRANS);
|
|
l.Transaction.delta = delta;
|
|
l.Transaction.uid = acct;
|
|
|
|
acceptLogEntry(l);
|
|
return log.writeEntry(l);
|
|
}
|
|
}
|
|
|
|
uint64_t PosDb::doTransaction(const uint32_t account, int32_t delta) {
|
|
LogEntry l = log.newLogEntry(ET_TRANS);
|
|
l.Transaction.delta = delta;
|
|
l.Transaction.uid = account;
|
|
|
|
acceptLogEntry(l);
|
|
return log.writeEntry(l);
|
|
}
|
|
|
|
uint64_t PosDb::doTransaction(std::string account, int32_t delta) {
|
|
return doTransaction(ns.get_id(account), delta);
|
|
}
|
|
|
|
uint64_t PosDb::revertTransaction(uint64_t serial) {
|
|
if(serial_to_object.find(serial) == serial_to_object.end()) {
|
|
return 0;
|
|
} else {
|
|
// do not double-revert transactions
|
|
sto_it p;
|
|
for(p = serial_to_object.begin(); p != serial_to_object.end(); ++p) {
|
|
if((p->second.type == ET_REVERT) && (p->second.Revert.revert_serial == serial))
|
|
break;
|
|
}
|
|
if(p != serial_to_object.end())
|
|
return 0;
|
|
|
|
LogEntry l = log.newLogEntry(ET_REVERT);
|
|
l.Revert.revert_serial = serial;
|
|
|
|
acceptLogEntry(l);
|
|
return log.writeEntry(l);
|
|
}
|
|
}
|
|
|
|
int32_t PosDb::getStock(uint64_t upc) {
|
|
uts_it p = upc_to_stock.find(upc);
|
|
if(p == upc_to_stock.end())
|
|
return 0;
|
|
else
|
|
return p->second;
|
|
}
|
|
|
|
uint64_t PosDb::doStockChange(uint64_t upc, int32_t delta) {
|
|
LogEntry l = log.newLogEntry(ET_SALE);
|
|
l.StockChange.delta = delta;
|
|
l.StockChange.upc = upc;
|
|
|
|
acceptLogEntry(l);
|
|
return log.writeEntry(l);
|
|
}
|
|
|
|
std::string PosDb::getUPCName(uint64_t upc) {
|
|
std::map<uint64_t, std::string>::iterator it = upc_to_name.find(upc);
|
|
if(it == upc_to_name.end()) return "UNKNOWN UPC";
|
|
return upc_to_name[upc];
|
|
}
|
|
|
|
|
|
uint64_t PosDb::setUPCName (uint64_t upc, std::string name) {
|
|
LogEntry l = log.newLogEntry(ET_ADDUPC);
|
|
l.AddUPC.upc = upc;
|
|
strncpy(l.AddUPC.name, name.c_str(), 32);
|
|
l.AddUPC.name[32] = 0;
|
|
|
|
acceptLogEntry(l);
|
|
return log.writeEntry(l);
|
|
}
|
|
|
|
std::vector<std::string> PosDb::toString() {
|
|
return log.toString();
|
|
}
|
|
|