fork download
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4.  
  5. class Expense{
  6. public:
  7. string expense_id;
  8. string trip_id;
  9. string amount_usd;
  10. string expense_type;
  11. string vendor_type;
  12. string vendor_name;
  13. };
  14.  
  15. class Violation{
  16. public :
  17. string expense_id;
  18. string message;
  19. };
  20.  
  21. class Rule{
  22. public:
  23. virtual bool violates(Expense e)=0;
  24. virtual string description()=0;
  25. virtual void finalize(vector<Violation> &violations){};
  26. };
  27.  
  28. class NoFieldRule : public Rule {
  29.  
  30. public :
  31. string fieldName;
  32. string fieldValue;
  33.  
  34.  
  35.  
  36. NoFieldRule(string fieldName,string fieldValue){
  37. this->fieldName = fieldName;
  38. this->fieldValue = fieldValue;
  39. }
  40.  
  41. string getField(Expense e, string fieldName){
  42. if(fieldName=="expense_id") return e.expense_id;
  43. if(fieldName=="trip_id") return e.trip_id;
  44. if(fieldName=="amount_usd") return e.amount_usd;
  45. if(fieldName=="expense_type") return e.expense_type;
  46. if(fieldName=="vendor_type") return e.vendor_type;
  47. if(fieldName=="vendor_name") return e.vendor_name;
  48. return "";
  49. }
  50.  
  51. bool violates(Expense e){
  52. return getField(e,fieldName)==fieldValue;
  53. }
  54.  
  55.  
  56. string description() override {
  57. return "No "+ fieldValue + " "+ fieldName +" expense allowed";
  58. }
  59. };
  60.  
  61. class FieldLimitRule : public Rule {
  62.  
  63. public :
  64.  
  65. string fieldName;
  66. string limit;
  67. string filterFieldName;
  68. string filterFieldValue;
  69.  
  70. FieldLimitRule(string fieldName,string limit,string filterFieldName="",string filterFieldValue=""){
  71. this->fieldName = fieldName;
  72. this->limit = limit;
  73. this->filterFieldName= filterFieldName;
  74. this->filterFieldValue = filterFieldValue;
  75. }
  76.  
  77. string getField(Expense e, string fieldName){
  78. if(fieldName=="expense_id") return e.expense_id;
  79. if(fieldName=="trip_id") return e.trip_id;
  80. if(fieldName=="amount_usd") return e.amount_usd;
  81. if(fieldName=="expense_type") return e.expense_type;
  82. if(fieldName=="vendor_type") return e.vendor_type;
  83. if(fieldName=="vendor_name") return e.vendor_name;
  84. return "";
  85. }
  86.  
  87. bool violates(Expense e){
  88. if(filterFieldName.empty())
  89. return stod(getField(e,fieldName))>stod(limit);
  90. else{
  91. string filterFieldValue = getField(e,filterFieldName);
  92. return filterFieldValue == this->filterFieldValue && stod(getField(e,fieldName)) > stod(limit);
  93. }
  94. }
  95.  
  96.  
  97. string description() override {
  98. if(!filterFieldName.empty()){
  99. return "No "+ filterFieldValue + " "+ fieldName +" expense can exceed "+ limit +"for " + fieldName;
  100. }
  101. else{
  102. return "No expense can exceed "+ limit +"for " + fieldName;
  103. }
  104.  
  105. }
  106. };
  107.  
  108. class AggregatedRule : public Rule {
  109. public :
  110.  
  111. string fieldName;
  112. string limit;
  113. string filterFieldName;
  114. string filterFieldValue;
  115. string groupField;
  116. unordered_map<string,double> totals;
  117.  
  118. AggregatedRule(string groupField,string fieldName,string limit,string filterFieldName="",string filterFieldValue=""){
  119. this->groupField = groupField;
  120. this->fieldName = fieldName;
  121. this->limit = limit;
  122. this->filterFieldName= filterFieldName;
  123. this->filterFieldValue = filterFieldValue;
  124. }
  125.  
  126. string getField(Expense e, string fieldName){
  127. if(fieldName=="expense_id") return e.expense_id;
  128. if(fieldName=="trip_id") return e.trip_id;
  129. if(fieldName=="amount_usd") return e.amount_usd;
  130. if(fieldName=="expense_type") return e.expense_type;
  131. if(fieldName=="vendor_type") return e.vendor_type;
  132. if(fieldName=="vendor_name") return e.vendor_name;
  133. return "";
  134. }
  135.  
  136. bool violates(Expense e){
  137. if(!filterFieldName.empty() && getField(e,filterFieldName)!=filterFieldValue){
  138. return false;
  139. }
  140. string value = getField(e,groupField);
  141. totals[value]+=stod(getField(e,fieldName));
  142. return false;
  143. }
  144.  
  145. void finalize(vector<Violation> &violations){
  146.  
  147. for(auto it : totals){
  148. string key = it.first;
  149. double value = it.second;
  150. string message = "";
  151. if(value>stod(limit)){
  152. if(!filterFieldName.empty()){
  153. message += key + " violates "+ filterFieldValue +" "+limit+".";
  154. }
  155. else{
  156. message += key + "violates " + limit+".";
  157. }
  158. violations.push_back({key,message});
  159. }
  160. }
  161. }
  162.  
  163.  
  164. string description() override {
  165. if(!filterFieldName.empty()){
  166. return "No "+ filterFieldValue + " "+ fieldName +" expense can exceed "+ limit +"for " + fieldName;
  167. }
  168. else{
  169. return "No expense can exceed "+ limit +"for " + fieldName;
  170. }
  171.  
  172. }
  173. };
  174.  
  175. vector<Violation> evaluate(vector<Rule*> rules, vector<Expense> expenses){
  176. vector<Violation> violations;
  177. for(auto expense: expenses){
  178. for(auto rule : rules){
  179. if(rule->violates(expense)){
  180. violations.push_back({expense.expense_id,rule->description()});
  181. }
  182. }
  183. }
  184. for(auto rule: rules){
  185. rule->finalize(violations);
  186. }
  187. return violations;
  188. }
  189.  
  190.  
  191.  
  192. int main(){
  193.  
  194.  
  195. vector<Expense> expenses = {
  196. {"e1","t1","50","meal","restaurant","Dominoes"},
  197. {"e2","t1","25","meal","restaurant","Sapphire"},
  198. {"e3","t2","200","airfare","transportation","Virgin_Atlantic"},
  199. {"e4","t2","120","entertainment","cinema","PVR"},
  200. {"e5","t2","58","client_hosting","restaurant","Saphire"},
  201. {"e6","t3","91","client_hosting","restaurant","Saphire"},
  202. {"e7","t1","2200","lodging","hotel","Marriot"}
  203. };
  204.  
  205. FieldLimitRule restaurantLimitRule("amount_usd","75","vendor_type","restaurant");
  206. NoFieldRule airfareRule("expense_type","airfare");
  207. NoFieldRule entertainmentRule("expense_type","entertainment");
  208. FieldLimitRule expenseLimitRule("amount_usd","2000");
  209. AggregatedRule tripExpenseRule("trip_id","amount_usd","2000");
  210. AggregatedRule tripMealRule("trip_id","amount_usd","200","expense_type","meal");
  211.  
  212. vector<Rule*> rules = {&restaurantLimitRule,&airfareRule,&entertainmentRule,&expenseLimitRule,&tripExpenseRule,&tripMealRule};
  213.  
  214. vector<Violation> violations = evaluate(rules,expenses);
  215.  
  216. for(auto violation : violations){
  217. cout<<"Id: "<<violation.expense_id<<" - "<<violation.message<<endl;
  218. }
  219.  
  220. return 0;
  221.  
  222. }
Success #stdin #stdout 0.01s 5312KB
stdin
Standard input is empty
stdout
Id: e3 - No airfare expense_type expense allowed
Id: e4 - No entertainment expense_type expense allowed
Id: e6 - No restaurant amount_usd expense can exceed 75for amount_usd
Id: e7 - No expense can exceed 2000for amount_usd
Id: t1 - t1violates 2000.