package crmdna.api.endpoint; import com.google.api.server.spi.config.Api; import com.google.api.server.spi.config.ApiMethod; import com.google.api.server.spi.config.ApiMethod.HttpMethod; import com.google.appengine.api.users.User; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import crmdna.client.Client; import crmdna.common.DateUtils; import crmdna.common.DateUtils.DateRange; import crmdna.common.UnitUtils.PhysicalQuantity; import crmdna.common.UnitUtils.ReportingUnit; import crmdna.common.Utils; import crmdna.common.Utils.Currency; import crmdna.common.api.APIResponse; import crmdna.common.api.APIResponse.Status; import crmdna.common.api.APIUtils; import crmdna.common.api.RequestInfo; import crmdna.email.EmailProp; import crmdna.email.GAEEmail; import crmdna.group.Group; import crmdna.hr.Department; import crmdna.inventory.*; import crmdna.inventory.MealCount.Meal; import crmdna.user.User.ResourceType; import javax.annotation.Nullable; import javax.inject.Named; import javax.servlet.http.HttpServletRequest; import java.util.*; import static crmdna.common.AssertUtils.ensure; @Api(name = "inventory") public class InventoryItemApi { @ApiMethod(path = "createInventoryItem", httpMethod = HttpMethod.POST) public APIResponse createInventoryItem(@Named("client") String client, @Nullable @Named("groupIdOrName") String groupIdOrName, @Named("inventoryItemTypeIdOrName") String inventoryItemTypeIdOrName, @Named("displayName") String displayName, @Named("physicalQuantity") PhysicalQuantity physicalQuantity, @Named("reportingUnit") ReportingUnit reportingUnit, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { if (client == null) client = "isha"; String login = null; try { Client.ensureValid(client); login = Utils.getLoginEmail(user); if (groupIdOrName == null) groupIdOrName = "mahamudra"; long groupId = 0; if (Utils.canParseAsLong(groupIdOrName)) { groupId = Utils.safeParseAsLong(groupIdOrName); } else { groupId = Group.safeGetByIdOrName(client, groupIdOrName).toProp().groupId; } ensure(groupId > 0); long inventoryItemTypeId = 0; if (Utils.canParseAsLong(inventoryItemTypeIdOrName)) { inventoryItemTypeId = Utils.safeParseAsLong(inventoryItemTypeIdOrName); } else { inventoryItemTypeId = InventoryItemType.safeGetByName(client, inventoryItemTypeIdOrName).toProp().inventoryItemTypeId; } ensure(inventoryItemTypeId > 0); InventoryItemProp prop = InventoryItem.create(client, groupId, inventoryItemTypeId, displayName, physicalQuantity, reportingUnit, login); return new APIResponse().status(Status.SUCCESS).object(prop); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } @ApiMethod(path = "updateInventoryItem", httpMethod = HttpMethod.POST) public APIResponse updateInventoryItem(@Named("client") String client, @Named("inventoryItemId") long inventoryItemId, @Nullable @Named("newInventoryItemTypeId") Long newInventoryItemTypeId, @Nullable @Named("newDisplayName") String newDisplayName, @Nullable @Named("newReportingUnit") ReportingUnit newReportingUnit, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { if (client == null) client = "isha"; String login = null; try { Client.ensureValid(client); login = Utils.getLoginEmail(user); InventoryItemProp prop = InventoryItem.update(client, inventoryItemId, newInventoryItemTypeId, newDisplayName, newReportingUnit, login); return new APIResponse().status(Status.SUCCESS).object(prop); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } @ApiMethod(path = "checkin", httpMethod = HttpMethod.POST) public APIResponse checkin(@Named("client") String client, @Named("inventoryItemIdOrName") String inventoryItemIdOrName, @Named("quantity") double qtyInReportingUnit, @Named("reportingUnit") ReportingUnit reportingUnit, @Named("pricePerReportingUnit") double pricePerReportingUnit, @Nullable @Named("dateDefaultCurrentTimestamp") Date date, @Nullable @Named("currencyDefaultINR") Currency ccy, @Nullable @Named("comment") String comment, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { String login = null; if (client == null) client = "isha"; if (ccy == null) ccy = Currency.INR; try { long inventoryItemId = 0; if (Utils.canParseAsLong(inventoryItemIdOrName)) { inventoryItemId = Utils.safeParseAsLong(inventoryItemIdOrName); } else { inventoryItemId = InventoryItem.safeGetByName(client, inventoryItemIdOrName).toProp().inventoryItemId; } login = Utils.getLoginEmail(user); InventoryCheckInProp prop = InventoryItem.checkIn(client, inventoryItemId, date, qtyInReportingUnit, reportingUnit, pricePerReportingUnit, ccy, comment, login); return new APIResponse().status(Status.SUCCESS).object(prop); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } @ApiMethod(path = "checkout", httpMethod = HttpMethod.POST) public APIResponse checkout(@Named("client") String client, @Named("inventoryItemIdOrName") String inventoryItemIdOrName, @Named("quantity") double qtyInReportingUnit, @Named("reportingUnit") ReportingUnit reportingUnit, @Nullable @Named("dateDefaultCurrentTimestamp") Date date, @Nullable @Named("unitPriceINR") Double pricePerReportingUnit, @Nullable @Named("departmentDropDown") IshaDepartment departmentDropDown, @Nullable @Named("departmentIdOrName") String departmentIdOrName, @Nullable @Named("meal") Meal meal, @Nullable @Named("comment") String comment, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { String login = null; if (client == null) client = "isha"; try { long inventoryItemId = 0; if (Utils.canParseAsLong(inventoryItemIdOrName)) { inventoryItemId = Utils.safeParseAsLong(inventoryItemIdOrName); } else { inventoryItemId = InventoryItem.safeGetByName(client, inventoryItemIdOrName).toProp().inventoryItemId; } ensure( (departmentDropDown != null) ^ (departmentIdOrName != null), "Either departmentDropDown or departmentIdOrName should be specified for check out (but not none or both)"); if (departmentDropDown != null) departmentIdOrName = departmentDropDown.toString(); Long departmentId = null; Set<String> tags = new HashSet<>(); if (departmentIdOrName != null) { if (Utils.canParseAsLong(departmentIdOrName)) { departmentId = Utils.safeParseAsLong(departmentIdOrName); } else { departmentId = Department.safeGetByName(client, departmentIdOrName).toProp().departmentId; } tags.add(ResourceType.DEPARTMENT + "||" + departmentId); } String departmentName = Department.safeGet(client, departmentId).toProp().displayName; if (departmentName.toUpperCase().contains("KITCHEN")) { ensure(meal != null, "Meal should be specified when checking out for [" + departmentName + "]"); tags.add(ResourceType.MEAL + "||" + meal); } login = Utils.getLoginEmail(user); InventoryCheckOutProp prop = InventoryItem.checkOut(client, inventoryItemId, date, qtyInReportingUnit, reportingUnit, pricePerReportingUnit, Currency.INR, comment, tags, login); return new APIResponse().status(Status.SUCCESS).object(prop); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } @ApiMethod(path = "getCurrentStockList", httpMethod = HttpMethod.GET) public APIResponse getCurrentStockList(@Named("client") String client, @Nullable @Named("groupIdOrName") String groupIdOrName, @Nullable @Named("sendEmailDefaultFalse") Boolean email, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { if (client == null) client = "isha"; if (groupIdOrName == null) groupIdOrName = "mahamudra"; String login = null; try { login = Utils.getLoginEmail(user); long groupId = 0; if (Utils.canParseAsLong(groupIdOrName)) { groupId = Utils.safeParseAsLong(groupIdOrName); } else { groupId = Group.safeGetByIdOrName(client, groupIdOrName).toProp().groupId; } InventoryItemQueryCondition qc = new InventoryItemQueryCondition(); qc.groupId = groupId; List<InventoryItemProp> props = InventoryItem.query(client, qc, login); InventoryItemProp.populateDependents(client, props); if (email == null) email = false; if (email) { EmailProp emailProp = new EmailProp(); String groupName = Group.safeGet(client, groupId).toProp().displayName; emailProp.attachmentName = "Stock list for " + groupName + ".csv"; emailProp.bodyHtml = "Stock list for " + groupName + " (as of this email timestamp)" + " is attached."; emailProp.csvAttachmentData = InventoryItemProp.toCSV(props); emailProp.subject = "Stock list for " + groupName; crmdna.user.User.ensureValidUser(client, login); emailProp.toEmailAddresses.add(login); GAEEmail.send(emailProp); } return new APIResponse().status(Status.SUCCESS).object(props); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } @ApiMethod(path = "deleteInventoryItem", httpMethod = HttpMethod.DELETE) public APIResponse deleteInventoryItem(@Named("client") String client, @Named("inventoryItemId") long inventoryItemId, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { if (client == null) client = "isha"; String login = null; try { login = Utils.getLoginEmail(user); InventoryItem.delete(client, inventoryItemId, login); return new APIResponse().status(Status.SUCCESS).message( "Inventory item [" + inventoryItemId + "] deleted"); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } @ApiMethod(path = "getStockChanges", httpMethod = HttpMethod.GET) public APIResponse getStockChanges(@Named("client") String client, @Nullable @Named("groupIdOrName") String groupIdOrName, @Nullable @Named("dateRange") DateRange dateRange, @Nullable @Named("startDateYYYYMMDD") Integer startYYYYMMDD, @Nullable @Named("endDateYYYYMMDD") Integer endYYYYMMDD, @Nullable @Named("inventoryItemTypeIdOrName") String inventoryItemTypeIdOrName, @Nullable @Named("departmentDropDown") IshaDepartment departmentDropDown, @Nullable @Named("departmentIdOrName") String departmentIdOrName, @Nullable @Named("meal") Meal meal, @Nullable @Named("inventoryItemIdOrName") String inventoryItemIdOrName, @Nullable @Named("sendEmailDefaultFalse") Boolean email, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { if (client == null) client = "isha"; String login = null; if (groupIdOrName == null) groupIdOrName = "mahamudra"; try { Client.ensureValid(client); login = Utils.getLoginEmail(user); ensure(((startYYYYMMDD == null) && (endYYYYMMDD == null)) || ((startYYYYMMDD != null) && (endYYYYMMDD != null)), "Both startYYYYMMDD and endYYYYMMDD should be specified (if dateRange is not specified)"); ensure( ((dateRange == null) && (startYYYYMMDD != null)) || ((dateRange != null) && (startYYYYMMDD == null)), "Either dateRange should be specified or (startYYYYMMDD and endYYYYMMDD) should be specified but not both"); long startMS = 0; long endMS; if (dateRange != null) { endMS = new Date().getTime(); startMS = endMS - DateUtils.getMilliSecondsFromDateRange(dateRange); } else { DateUtils.ensureFormatYYYYMMDD(startYYYYMMDD); DateUtils.ensureFormatYYYYMMDD(endYYYYMMDD); ensure(endYYYYMMDD >= startYYYYMMDD, "End date should be greater or equal to start date"); startMS = DateUtils.toDate(startYYYYMMDD).getTime(); endMS = DateUtils.toDate(endYYYYMMDD).getTime(); } ensure(startMS != 0, "Start date cannot be 0"); ensure(endMS != 0, "End date cannot be 0"); ensure(endMS >= startMS, "End date should be greater or equal to start date"); long groupId; if (Utils.canParseAsLong(groupIdOrName)) { groupId = Utils.safeParseAsLong(groupIdOrName); } else { groupId = Group.safeGetByIdOrName(client, groupIdOrName).toProp().groupId; } ensure(groupId > 0); Long inventoryItemTypeId = null; if (inventoryItemTypeIdOrName != null) { if (Utils.canParseAsLong(inventoryItemTypeIdOrName)) { inventoryItemTypeId = Utils.safeParseAsLong(inventoryItemTypeIdOrName); } else { inventoryItemTypeId = InventoryItemType.safeGetByName(client, inventoryItemTypeIdOrName).toProp().inventoryItemTypeId; } ensure(inventoryItemTypeId > 0); } ensure( (departmentDropDown != null) ^ (departmentIdOrName != null), "Either departmentDropDown or departmentIdOrName should be specified for check out (but not none or both)"); if (departmentDropDown != null) departmentIdOrName = departmentDropDown.toString(); Long departmentId = null; Set<String> tags = new HashSet<>(); if (departmentIdOrName != null) { if (Utils.canParseAsLong(departmentIdOrName)) { departmentId = Utils.safeParseAsLong(departmentIdOrName); } else { departmentId = Department.safeGetByName(client, departmentIdOrName).toProp().departmentId; } tags.add(ResourceType.DEPARTMENT + "||" + departmentId); ensure(departmentId > 0); } if (meal != null) tags.add(ResourceType.MEAL + "||" + meal); Long inventoryItemId = null; if (inventoryItemIdOrName != null) { if (Utils.canParseAsLong(inventoryItemIdOrName)) { inventoryItemId = Utils.safeParseAsLong(inventoryItemIdOrName); } else { inventoryItemId = InventoryItem.safeGetByName(client, inventoryItemIdOrName).toProp().inventoryItemId; } ensure(inventoryItemId > 0); } StockChangeQueryCondition qc = new StockChangeQueryCondition(groupId, startMS, endMS); if (departmentId != null) qc.tags = tags; if (inventoryItemId != null) qc.inventoryItemIds.add(inventoryItemId); if (inventoryItemTypeId != null) qc.inventoryItemTypeIds.add(inventoryItemTypeId); qc.includeCheckIn = true; qc.includeCheckOut = true; List<StockChangeProp> props = InventoryItem.queryStockChanges(client, qc, login); if (email == null) email = false; if (email) { crmdna.user.User.ensureValidUser(client, login); EmailProp emailProp = new EmailProp(); String groupName = Group.safeGet(client, groupId).toProp().displayName; emailProp.attachmentName = "Stock changes for " + groupName + ".csv"; Gson gson = new GsonBuilder().setPrettyPrinting().create(); emailProp.bodyHtml = "Stock changes for " + groupName + " is attached. <br><br><span style=\"color:grey\">Condition: " + gson.toJson(qc) + "</span>"; emailProp.csvAttachmentData = StockChangeProp.toCSV(props); emailProp.subject = "Stock changes for " + groupName; emailProp.toEmailAddresses.add(login); GAEEmail.send(emailProp); } return new APIResponse() .status(Status.SUCCESS) .message( "QueryCondition: [" + new Gson().toJson(qc) + "]. No of changes: " + props.size()) .object(props); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } @ApiMethod(path = "setKitchen3MealCount", httpMethod = HttpMethod.POST) public APIResponse setKitchen3MealCount(@Named("client") String client, @Named("yyyymmdd") int yyyymmdd, @Nullable @Named("breakfastCount") Integer breakfastCount, @Nullable @Named("lunchCount") Integer lunchCount, @Nullable @Named("dinnerCount") Integer dinnerCount, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { if (client == null) client = "isha"; String login = null; try { Client.ensureValid(client); login = Utils.getLoginEmail(user); MealCountProp prop = MealCount.setCount(client, yyyymmdd, breakfastCount, lunchCount, dinnerCount, login); return new APIResponse().status(Status.SUCCESS).object(prop); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } @ApiMethod(path = "queryKitchen3CostPerMeal", httpMethod = HttpMethod.GET) public APIResponse queryKitchen3CostPerMeal(@Named("client") String client, @Nullable @Named("startYYYYMMDD") Integer startYYYYMMDD, @Nullable @Named("endYYYYMMDD") Integer endYYYYMMDD, @Nullable @Named("sendEmailDefaultFalse") Boolean email, @Nullable @Named("showStackTrace") Boolean showStackTrace, HttpServletRequest req, User user) { if (client == null) client = "isha"; String login = null; try { Client.ensureValid(client); login = Utils.getLoginEmail(user); List<MealCountEntity> entities = MealCount.query(client, startYYYYMMDD, endYYYYMMDD); List<MealCountProp> props = new ArrayList<>(); for (MealCountEntity entity : entities) { props.add(entity.toProp()); } long groupId = Group.safeGetByIdOrName(client, "Mahamudra").toProp().groupId; props = IshaInventoryHelper.getKitchen3DailyMealCost(client, groupId, startYYYYMMDD, endYYYYMMDD, login); if (email == false) email = true; if (email) { EmailProp emailProp = new EmailProp(); emailProp.attachmentName = "Meal count(s) for Kitchen 3.csv"; emailProp.bodyHtml = "See attached spreadsheet for kitchen 3 meal count. <br><br>" + "Start date: " + (startYYYYMMDD != null ? startYYYYMMDD : "Not specified") + "<br>" + "End date: " + (endYYYYMMDD != null ? endYYYYMMDD : "Not specified"); emailProp.csvAttachmentData = MealCountProp.getCSV(props); emailProp.subject = "Meal count(s) for Kitchen 3"; crmdna.user.User.ensureValidUser(client, login); emailProp.toEmailAddresses.add(login); GAEEmail.send(emailProp); } return new APIResponse().status(Status.SUCCESS).object(props); } catch (Exception ex) { return APIUtils.toAPIResponse(ex, showStackTrace, new RequestInfo().client(client).req(req) .login(login)); } } public enum IshaDepartment { KITCHEN_3_MAHAMUDRA, NANDI_FOODS } }