From 40933a2713abcbf95671ecb652ba7ad4908df815 Mon Sep 17 00:00:00 2001 From: "gowthaman.b" Date: Thu, 8 Feb 2024 17:50:08 +0530 Subject: [PATCH] some updates --- api.log | 4 + .../kotlin/com/restapi/AppAccessManager.kt | 2 +- src/main/kotlin/com/restapi/Main.kt | 86 +++--- src/main/kotlin/com/restapi/config/Auth.kt | 2 +- .../com/restapi/controllers/Entities.kt | 266 +++++++++++------- .../kotlin/com/restapi/controllers/Excel.kt | 2 +- src/main/kotlin/com/restapi/domain/models.kt | 95 ++++--- src/main/resources/dbmigration/1.5.sql | 2 + .../resources/dbmigration/model/1.5.model.xml | 11 + src/main/resources/logback.xml | 16 ++ 10 files changed, 301 insertions(+), 185 deletions(-) create mode 100644 api.log create mode 100644 src/main/resources/dbmigration/1.5.sql create mode 100644 src/main/resources/dbmigration/model/1.5.model.xml diff --git a/api.log b/api.log new file mode 100644 index 0000000..ff38f0e --- /dev/null +++ b/api.log @@ -0,0 +1,4 @@ +17:49:29.421 [main] INFO io.ebean - ebean version: 13.23.2 +17:49:29.469 [main] INFO io.avaje.config - Loaded properties from [] +17:49:29.513 [main] INFO io.ebean.core - offline platform [POSTGRES] +17:49:29.918 [main] INFO io.ebean.core - Started database[db] platform[POSTGRES] in 428ms diff --git a/src/main/kotlin/com/restapi/AppAccessManager.kt b/src/main/kotlin/com/restapi/AppAccessManager.kt index ad84c1d..de65e6b 100644 --- a/src/main/kotlin/com/restapi/AppAccessManager.kt +++ b/src/main/kotlin/com/restapi/AppAccessManager.kt @@ -42,7 +42,7 @@ class AppAccessManager : AccessManager { Role.DbOps -> listOf("ROLE_DB_OPS") Role.Entity -> loadEntityActionRole(entity, action) is Role.Standard -> role.action.toList().map { "ROLE_${entity}_${it}" } - is Role.Explicit -> role.roles + is Role.Explicit -> role.roles.toList() + listOf("ROLE_ADMIN") }.map(String::uppercase) } diff --git a/src/main/kotlin/com/restapi/Main.kt b/src/main/kotlin/com/restapi/Main.kt index 3e253bf..b2d963d 100644 --- a/src/main/kotlin/com/restapi/Main.kt +++ b/src/main/kotlin/com/restapi/Main.kt @@ -110,56 +110,54 @@ fun main(args: Array) { it.json(mapOf("status" to true)) } - path("/vendor"){ - path("/"){ - post("", VendorCtrl::create, Roles(Role.Explicit(listOf("ROLE_VENDOR_CREATE", "ROLE_ADMIN")))) - post("/batch", VendorCtrl::createBatch, Roles(Role.Explicit(listOf("ROLE_VENDOR_CREATE", "ROLE_ADMIN")))) - get("/{id}", VendorCtrl::get, Roles(Role.Explicit(listOf("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE", "ROLE_ADMIN")))) - post("/getAll", VendorCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE")))) - get("quotes/{id}", VendorCtrl::getQuotes, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE", "ROLE_VENDOR_VIEW")))) - get("pos/{id}", VendorCtrl::getPos, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_PO_VIEW", "ROLE_PO_CREATE`")))) - put("/rate/{id}/{rating}", VendorCtrl::rate, Roles(Role.Explicit(listOf("ROLE_VENDOR_CREATE", "ROLE_ADMIN")))) + path("/vendor") { + path("/") { + post("", VendorCtrl::create, Roles(Role.Explicit("ROLE_VENDOR_CREATE"))) + post("/batch", VendorCtrl::createBatch, Roles(Role.Explicit("ROLE_VENDOR_CREATE"))) + get("/{id}", VendorCtrl::get, Roles(Role.Explicit("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE"))) + post("/getAll", VendorCtrl::getAll, Roles(Role.Explicit("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE"))) + get("quotes/{id}", VendorCtrl::getQuotes, Roles(Role.Explicit("ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE", "ROLE_VENDOR_VIEW"))) + get("pos/{id}", VendorCtrl::getPos, Roles(Role.Explicit("ROLE_PO_VIEW", "ROLE_PO_CREATE`"))) + put("/rate/{id}/{rating}", VendorCtrl::rate, Roles(Role.Explicit("ROLE_VENDOR_CREATE"))) } - path("/po"){ - get("/next", PurchaseOrderCtrl::getNextNum, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_ADMIN")))) - post("", PurchaseOrderCtrl::create, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_ADMIN")))) - post("/batch", PurchaseOrderCtrl::createBatch, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_ADMIN")))) - post("/getAll", PurchaseOrderCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_VENDOR_CREATE", "ROLE_ADMIN")))) - get("/{id}", PurchaseOrderCtrl::get, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_QUOTE_CREATE")))) - put("/approve/{id}", PurchaseOrderCtrl::approve, Roles(Role.Explicit(listOf("ROLE_ADMIN")))) - put("/reject/{id}", PurchaseOrderCtrl::reject, Roles(Role.Explicit(listOf("ROLE_ADMIN")))) - get("/refQuote/{id}", PurchaseOrderCtrl::quoteReference, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_ADMIN")))) + path("/po") { + get("/next", PurchaseOrderCtrl::getNextNum, Roles(Role.Explicit("ROLE_PO_CREATE"))) + post("", PurchaseOrderCtrl::create, Roles(Role.Explicit("ROLE_PO_CREATE"))) + post("/batch", PurchaseOrderCtrl::createBatch, Roles(Role.Explicit("ROLE_PO_CREATE"))) + post("/getAll", PurchaseOrderCtrl::getAll, Roles(Role.Explicit("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_VENDOR_CREATE"))) + get("/{id}", PurchaseOrderCtrl::get, Roles(Role.Explicit("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_QUOTE_CREATE"))) + put("/approve/{id}", PurchaseOrderCtrl::approve, Roles(Role.Explicit())) + put("/reject/{id}", PurchaseOrderCtrl::reject, Roles(Role.Explicit())) + get("/refQuote/{id}", PurchaseOrderCtrl::quoteReference, Roles(Role.Explicit("ROLE_PO_CREATE"))) } - path("/quote"){ - get("/next", QuotationCtrl::getNextNum, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN")))) - post("", QuotationCtrl::create, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN")))) - post("/batch", QuotationCtrl::createBatch, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN")))) - post("/getAll", QuotationCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN", "ROLE_QUOTE_VIEW")))) - get("/{id}", QuotationCtrl::get, Roles(Role.Explicit(listOf("ROLE_QUOTE_VIEW", "ROLE_ADMIN", "ROLE_QUOTE_CREATE")))) - delete("/{id}", QuotationCtrl::delete, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN")))) + path("/quote") { + get("/next", QuotationCtrl::getNextNum, Roles(Role.Explicit("ROLE_QUOTE_CREATE"))) + post("", QuotationCtrl::create, Roles(Role.Explicit("ROLE_QUOTE_CREATE"))) + post("/batch", QuotationCtrl::createBatch, Roles(Role.Explicit("ROLE_QUOTE_CREATE"))) + post("/getAll", QuotationCtrl::getAll, Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_QUOTE_VIEW"))) + get("/{id}", QuotationCtrl::get, Roles(Role.Explicit("ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE"))) + delete("/{id}", QuotationCtrl::delete, Roles(Role.Explicit("ROLE_QUOTE_CREATE"))) } - path("/product"){ - post("", ProductCtrl::create, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN")))) - //get("/{hsnCode}", ProductCtrl::get, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN")))) - put("/{id}", ProductCtrl::update, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN")))) - //patch("/{id}", ProductCtrl::patch, Roles(Role.Explicit(listOf("ROLE_PRODUCT_UPDATE", "ROLE_ADMIN")))) - delete("/{id}", ProductCtrl::delete, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN")))) - get("", ProductCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN")))) - get("/{id}", ProductCtrl::get, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN")))) - post("/getAll", ProductCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN")))) + path("/product") { + post("", ProductCtrl::create, Roles(Role.Explicit("ROLE_PRODUCT_CREATE"))) + put("/{id}", ProductCtrl::update, Roles(Role.Explicit("ROLE_PRODUCT_CREATE"))) + delete("/{id}", ProductCtrl::delete, Roles(Role.Explicit("ROLE_PRODUCT_CREATE"))) + patch("/{id}", ProductCtrl::patch, Roles(Role.Explicit("ROLE_PRODUCT_CREATE"))) + get("", ProductCtrl::getAll, Roles(Role.Explicit("ROLE_PRODUCT_VIEW"))) + get("/{id}", ProductCtrl::get, Roles(Role.Explicit("ROLE_PRODUCT_VIEW"))) } - path("/doc"){ - post("", Document::create, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE", "ROLE_ADMIN")))) + path("/doc") { + post("", DocumentCtrl::create, Roles(Role.Explicit("ROLE_DOC_CREATE"))) //why type and refid are clubbed ?? - get("/{type}/{refId}", Document::getWithRefId, Roles(Role.Explicit(listOf("ROLE_DOC_VIEW", "ROLE_ADMIN", "ROLE_PRODUCT_CREATE")))) - get("/{id}", Document::get, Roles(Role.Explicit(listOf("ROLE_DOC_VIEW", "ROLE_ADMIN", "ROLE_PRODUCT_CREATE")))) - get("/print/{id}", Document::print, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE", "ROLE_DOC_VIEW")))) - delete("/{id}", Document::delete, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE")))) + get("/{type}/{refId}", DocumentCtrl::getWithRefId, Roles(Role.Explicit("ROLE_DOC_VIEW", "ROLE_PRODUCT_CREATE"))) + get("/{id}", DocumentCtrl::get, Roles(Role.Explicit("ROLE_DOC_VIEW", "ROLE_PRODUCT_CREATE"))) + get("/print/{id}", DocumentCtrl::print, Roles(Role.Explicit("ROLE_DOC_CREATE", "ROLE_DOC_VIEW"))) + delete("/{id}", DocumentCtrl::delete, Roles(Role.Explicit("ROLE_DOC_CREATE"))) } - path("/reqForQuote"){ - post("", RequestForQuote::create, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE", "ROLE_ADMIN")))) - get("/{id}", RequestForQuote::get, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE", "ROLE_RFQ_VIEW", "ROLE_QUOTE_VIEW", "ROLE_PO_VIEW", "ROLE_ADMIN")))) - put("/{id}", RequestForQuote::update, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE", "ROLE_ADMIN")))) + path("/reqForQuote") { + post("", RequestForQuote::create, Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE"))) + get("/{id}", RequestForQuote::get, Roles(Role.Explicit("ROLE_RFQ_CREATE", "ROLE_RFQ_VIEW", "ROLE_QUOTE_VIEW", "ROLE_PO_VIEW"))) + put("/{id}", RequestForQuote::update, Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE"))) } } post("/script/database/{name}", Entities::executeStoredProcedure, Roles(adminRole, Role.DbOps)) diff --git a/src/main/kotlin/com/restapi/config/Auth.kt b/src/main/kotlin/com/restapi/config/Auth.kt index f42e6fc..a48201b 100644 --- a/src/main/kotlin/com/restapi/config/Auth.kt +++ b/src/main/kotlin/com/restapi/config/Auth.kt @@ -235,7 +235,7 @@ enum class Action { sealed class Role { open class Standard(vararg val action: Action) : Role() data object Entity : Role() - data class Explicit(val roles: List) : Role() + open class Explicit(vararg val roles: String) : Role() data object DbOps : Role() } diff --git a/src/main/kotlin/com/restapi/controllers/Entities.kt b/src/main/kotlin/com/restapi/controllers/Entities.kt index 715297a..9b95866 100644 --- a/src/main/kotlin/com/restapi/controllers/Entities.kt +++ b/src/main/kotlin/com/restapi/controllers/Entities.kt @@ -6,13 +6,9 @@ import com.fasterxml.jackson.databind.JsonDeserializer import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.restapi.domain.* -import com.restapi.domain.Product -import com.restapi.domain.PurchaseOrder -import com.restapi.domain.Quotation import com.restapi.domain.Session.currentUser import com.restapi.domain.Session.database import com.restapi.domain.Session.findDataModelByEntityAndUniqId -import com.restapi.domain.Vendor import com.restapi.integ.Scripting import io.ebean.CallableSql import io.ebean.RawSqlBuilder @@ -373,12 +369,13 @@ object Entities { false } } -data class Filters(val common :CommonFilters, val custom :CustomFilters) -data class SequenceNumber(val number:String) -data class BatchPos(val pos :List) + +data class Filters(val common: CommonFilters, val custom: CustomFilters) +data class SequenceNumber(val number: String) +data class BatchPos(val pos: List) object PurchaseOrderCtrl { - fun getNextNum(ctx: Context){ + fun getNextNum(ctx: Context) { val prefix = "PO/" val cnt = database.find(PurchaseOrder::class.java) .findCount() @@ -387,39 +384,45 @@ object PurchaseOrderCtrl { val seq = SequenceNumber(prefix + cnt) ctx.json(seq).status(HttpStatus.OK) } - fun get(ctx :Context){ + + fun get(ctx: Context) { val id = ctx.pathParam("id") val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("po not found for $id") ctx.json(po).status(HttpStatus.OK) } + data class PF(val common: CommonFilters, val poFilters: POFilters) - fun getAll(ctx :Context){ + + fun getAll(ctx: Context) { val filters = ctx.bodyAsClass() val pos = searchPos(filters.common, filters.poFilters) ctx.json(pos).status(HttpStatus.OK) } - fun create(ctx :Context){ + + fun create(ctx: Context) { val po = ctx.bodyAsClass() database.save(po) ctx.json(po).status(HttpStatus.CREATED) } - fun createBatch(ctx :Context){ - val pos = ctx.bodyAsClass>() - val txn = database.beginTransaction() - try { - txn.isBatchMode = true - for(po in pos) database.save(po) - txn.commit() - ctx.status(HttpStatus.CREATED).result("POS Created") - } catch(e :Exception){ - txn.rollback() - ctx.status(HttpStatus.INTERNAL_SERVER_ERROR).result("Pos Creation failed" + e.message) - } finally { - txn.end() - } - ctx.result("pos batch created").status(HttpStatus.CREATED) + + fun createBatch(ctx: Context) { + val pos = ctx.bodyAsClass>() + val txn = database.beginTransaction() + try { + txn.isBatchMode = true + for (po in pos) database.save(po) + txn.commit() + ctx.status(HttpStatus.CREATED).result("POS Created") + } catch (e: Exception) { + txn.rollback() + ctx.status(HttpStatus.INTERNAL_SERVER_ERROR).result("Pos Creation failed" + e.message) + } finally { + txn.end() + } + ctx.result("pos batch created").status(HttpStatus.CREATED) } - fun approve(ctx :Context){ + + fun approve(ctx: Context) { val id = ctx.pathParam("id") val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("po not found for $id") po.approvalStatus = ApprovalStatus.APPROVED @@ -427,14 +430,16 @@ object PurchaseOrderCtrl { ctx.json(po).status(HttpStatus.CREATED) //reject all other pos pertaining to the same tx ?? } - fun reject(ctx :Context){ + + fun reject(ctx: Context) { val id = ctx.pathParam("id") val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("po not found for $id") po.approvalStatus = ApprovalStatus.REJECTED po.save() ctx.json(po).status(HttpStatus.CREATED) } - fun quoteReference(ctx :Context){ + + fun quoteReference(ctx: Context) { //gets the quote reference on which this po is based on val id = ctx.pathParam("id") val quote = database.find(Quotation::class.java) @@ -451,7 +456,7 @@ data class ProductSearch( ) object ProductCtrl { - fun get(ctx :Context){ + fun get(ctx: Context) { val id = ctx.pathParam("id") val product = database.find(Product::class.java) .where() @@ -462,14 +467,16 @@ object ProductCtrl { println(product) ctx.json(product).status(HttpStatus.OK) } - fun getAll(ctx: Context){ + + fun getAll(ctx: Context) { val productList = Session.database.find(Product::class.java) .findList() - .sortedBy { it.hsnCode } + .sortedBy { it.name } ctx.json(productList) } - fun create(ctx :Context){ + + fun create(ctx: Context) { val product = ctx.bodyAsClass() database.save(product) ctx.json(product).status(HttpStatus.CREATED) @@ -477,21 +484,62 @@ object ProductCtrl { fun delete(ctx: Context) { val id = ctx.pathParam("id") - val product = database.delete(Product::class.java, id) + database.delete(Product::class.java, id) } fun patch(ctx: Context) { + val id = ctx.pathParam("id") + val patchValues = ctx.bodyAsClass>() + database.beginTransaction().use { + patchValues.entries.forEach { en -> + val key = en.key + val value = en.value + database.sqlUpdate("update products set $key = ? where id = ?").apply { + setParameter(1, value) + setParameter(2, id) + execute() + } + } + it.commit() + } } fun update(ctx: Context) { val id = ctx.pathParam("id") + val product = database.find(Product::class.java, id) ?: throw NotFoundResponse("product not found for $id") + val updatedProduct = ctx.bodyAsClass() + product.patchValues(updatedProduct) + product.update() } + + + @JvmStatic + fun main(args: Array) { + + val patchValues = mapOf("name" to 1) + val id = 1; + database.beginTransaction().use { + patchValues.entries.forEach { en -> + val key = en.key + val value = en.value + + database.sqlUpdate("update product set $key = ? where sys_pk = ?").apply { + setParameter(1, value) + setParameter(2, id) + + execute() + } + } + it.commit() + } + } + } object QuotationCtrl { - fun getNextNum(ctx: Context){ + fun getNextNum(ctx: Context) { val prefix = "QUOTE/" val cnt = database.find(Quotation::class.java) .findCount() @@ -500,33 +548,37 @@ object QuotationCtrl { val seq = SequenceNumber(prefix + cnt) ctx.json(seq).status(HttpStatus.OK) } - fun get(ctx :Context){ + + fun get(ctx: Context) { val id = ctx.pathParam("id") - val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for $id") + val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for $id") ctx.status(HttpStatus.OK) ctx.json(quote) } + data class QF(val common: CommonFilters, val quoteFilters: QuoteFilters) - fun getAll(ctx :Context){ + + fun getAll(ctx: Context) { val filters = ctx.bodyAsClass() val quotes = searchQuotes(filters.common, filters.quoteFilters) ctx.json(quotes).status(HttpStatus.OK) } - fun create(ctx :Context){ + fun create(ctx: Context) { val quote = ctx.bodyAsClass() database.save(quote) ctx.json(quote).status(HttpStatus.CREATED) } - fun createBatch(ctx :Context){ + + fun createBatch(ctx: Context) { val quotes = ctx.bodyAsClass>() - val txn = database.beginTransaction() + val txn = database.beginTransaction() try { txn.isBatchMode = true - for(quote in quotes) database.save(quote) + for (quote in quotes) database.save(quote) txn.commit() ctx.status(HttpStatus.CREATED).result("Quotes Created") - } catch(e :Exception){ + } catch (e: Exception) { txn.rollback() ctx.status(HttpStatus.INTERNAL_SERVER_ERROR).result("Quotes Creation failed" + e.message) } finally { @@ -534,134 +586,146 @@ object QuotationCtrl { } ctx.result("Quotes batch created").status(HttpStatus.CREATED) } - fun delete(ctx :Context){ + + fun delete(ctx: Context) { val id = ctx.pathParam("id") - val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for id $id") + val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for id $id") quote.delete() ctx.status(HttpStatus.OK) ctx.result("quote with $id deleted") } - fun generatePO(ctx :Context){ + + fun generatePO(ctx: Context) { //user should be redirected to a po form submission with prefilled values //create a PO object with values from the quote and then send it as body to vendor/po/create ?? } - fun reqForQuote(ctx :Context){ - val reqForQuoteNum = ctx.pathParam(("rfqNum")) + + fun reqForQuote(ctx: Context) { + val reqForQuoteNum = ctx.pathParam(("rfqNum")) val rfq = database.find(RequestForQuote::class.java) - .where() - .eq("reqForQuoteNum", reqForQuoteNum) - ?: throw NotFoundResponse("request for quote not found for this quotation") + .where() + .eq("reqForQuoteNum", reqForQuoteNum) + ?: throw NotFoundResponse("request for quote not found for this quotation") ctx.status(HttpStatus.OK) ctx.json(rfq) } } -object Document { - fun get(ctx :Context){ - val id = ctx.pathParam("id") + +object DocumentCtrl { + fun get(ctx: Context) { + val id = ctx.pathParam("id") val doc = database.find(Document::class.java, id) ?: throw NotFoundResponse("no doc found with id $id") ctx.status(HttpStatus.OK) ctx.json(doc) } - fun create(ctx :Context){ - val doc = ctx.bodyAsClass() + + fun create(ctx: Context) { + val doc = ctx.bodyAsClass() database.save(doc) ctx.status(HttpStatus.CREATED) ctx.json(doc) } - fun print(ctx :Context){ + + fun print(ctx: Context) { //would be handled in the frontend ?? } - fun delete(ctx :Context){ + + fun delete(ctx: Context) { val id = ctx.pathParam("id") - val doc = database.find(Document::class.java, id) ?: throw NotFoundResponse("no doc found with id $id") + val doc = database.find(Document::class.java, id) ?: throw NotFoundResponse("no doc found with id $id") //doc.delete() ctx.status(HttpStatus.OK) ctx.result("document deleted with id $id") } - fun getWithRefId(ctx :Context){ + + fun getWithRefId(ctx: Context) { //fetches a particular doc (po, quote) with ref id val refId = ctx.pathParam("refId") val doc = database.find(Document::class.java) .where() - .eq("refId", refId) + .eq("typeOfDoc", DocType.valueOf(ctx.pathParam("type"))) + .eq("refIdOfDoc", refId) ?: throw NotFoundResponse("no doc found for refId $refId") ctx.status(HttpStatus.OK) ctx.json(doc) } } + object VendorCtrl { - fun get(ctx :Context){ - val id = ctx.pathParam("id") + val logger = LoggerFactory.getLogger("Vendor") + fun get(ctx: Context) { + val id = ctx.pathParam("id") val vendor = database.find(Vendor::class.java, id) ?: throw NotFoundResponse("no vendor found with id $id") ctx.status(HttpStatus.OK) ctx.json(vendor) } - data class VF(val common : CommonFilters, val vendorFilters: VendorFilters) - fun getAll(ctx :Context){ + + data class VF(val common: CommonFilters, val vendorFilters: VendorFilters) + + fun getAll(ctx: Context) { val filters = ctx.bodyAsClass() - println(filters.common) - println(filters.vendorFilters) + logger.info("filters = {}", filters) val pos = searchVendors(filters.common, filters.vendorFilters) ctx.status(HttpStatus.OK) ctx.json(pos) } - fun createBatch(ctx: Context){ + + fun createBatch(ctx: Context) { val vendors = ctx.bodyAsClass>() - val txn = database.beginTransaction() - try { - txn.isBatchMode = true - for(v in vendors) database.save(v) - txn.commit() - ctx.status(HttpStatus.CREATED).result("Vendors Created") - } catch(e :Exception){ - txn.rollback() - ctx.status(HttpStatus.INTERNAL_SERVER_ERROR).result("Vendor Creation failed" + e.message) - } finally { - txn.end() - } + database.saveAll(vendors) } - fun create(ctx :Context){ + + fun create(ctx: Context) { val vendor = ctx.bodyAsClass() database.save(vendor) ctx.status(HttpStatus.CREATED) ctx.json(vendor) } - fun update(ctx :Context){ + + fun update(ctx: Context) { } - fun delete(ctx :Context){ - } - fun getQuotes(ctx :Context){ + fun delete(ctx: Context) { val id = ctx.pathParam("id") + val vendor = database.find(Vendor::class.java, id) ?: throw NotFoundResponse("no vendor found with id $id") + database.delete(vendor) + ctx.status(HttpStatus.OK) + } + + fun getQuotes(ctx: Context) { + val id = ctx.pathParam("id").toLong() val quotes = database.find(Quotation::class.java) .where() - .eq("vendor", id) + .eq("vendor", database.find(Vendor::class.java, id) ?: throw NotFoundResponse("vendor not found for $id")) .findList() - ctx.status(HttpStatus.OK) - ctx.json(quotes) + ctx.json(quotes).status(HttpStatus.OK) } - fun getPos(ctx :Context){ - val id = ctx.pathParam("id") + + fun getPos(ctx: Context) { + val id = ctx.pathParam("id").toLong() val pos = database.find(PurchaseOrder::class.java) .where() - .eq("vendor", id) + .eq("vendor", database.find(Vendor::class.java, id) ?: throw NotFoundResponse("vendor not found for $id")) .findList() - ctx.status(HttpStatus.OK) - ctx.json(pos) + ctx.json(pos).status(HttpStatus.OK) } - fun rate(ctx :Context){ + + fun rate(ctx: Context) { val id = ctx.pathParam("id") - val rating = ctx.pathParam("rating").toDouble() - val vendor = database.find(Vendor::class.java, id) ?: throw NotFoundResponse("vendor not found for id $id") - //could place some rating validation checks - vendor.rating = rating - vendor.save() - ctx.status(HttpStatus.OK) - ctx.result("rating changed") + val rating1 = ctx.pathParam("rating").toDouble() + + database.find(Vendor::class.java, id)?.let { + it.rating = rating1 + it.save() + } ?: throw NotFoundResponse("vendor not found for id $id") + + + ctx.result("rating changed").status(HttpStatus.OK) } } + object RequestForQuote { fun create(ctx: Context) { val rfq = ctx.bodyAsClass() diff --git a/src/main/kotlin/com/restapi/controllers/Excel.kt b/src/main/kotlin/com/restapi/controllers/Excel.kt index 6cd621b..833cbd0 100644 --- a/src/main/kotlin/com/restapi/controllers/Excel.kt +++ b/src/main/kotlin/com/restapi/controllers/Excel.kt @@ -411,7 +411,7 @@ fun ImportFromExcel(fileType: FileType, filePath : String) { "invoice" -> DocType.INVOICE else -> DocType.ALL } - doc.refId = refId + doc.refIdOfDoc = refId.toLong() doc.url = url } } diff --git a/src/main/kotlin/com/restapi/domain/models.kt b/src/main/kotlin/com/restapi/domain/models.kt index a861a24..7ccea58 100644 --- a/src/main/kotlin/com/restapi/domain/models.kt +++ b/src/main/kotlin/com/restapi/domain/models.kt @@ -12,7 +12,7 @@ import java.time.LocalDateTime import javax.persistence.* data class Comments(val text: String = "", val by: String = "", val at: LocalDateTime = LocalDateTime.now()) -data class POProducts(val productId: String = "", val productName: String = "", val unitPrice :Double = 0.0, val quantity: Double = 0.0, val description :String = "") +data class POProducts(val productId: String = "", val productName: String = "", val unitPrice: Double = 0.0, val quantity: Double = 0.0, val description: String = "") enum class ApprovalStatus { @@ -218,7 +218,6 @@ open class DataModel : BaseTenantModel() { } - @Entity @Index(unique = true, name = "unique_session_id", columnNames = ["session_id"]) open class AnonSession : BaseTenantModel() { @@ -244,29 +243,35 @@ class SafeStringDeserializer : JsonDeserializer() { } data class ContactPerson(val name: String = "", val email: String = "", val mobile: String = "") + @Entity -open class Vendor :BaseTenantModel() { - var name :String = "" - var msme :String = "" - var gstNumber :String = "" - var address :String = "" - var rating :Double = 0.0 +open class Vendor : BaseTenantModel() { + var name: String = "" + var msme: String = "" + var gstNumber: String = "" + var address: String = "" + var rating: Double = 0.0 + @DbJsonB - var contacts :List = mutableListOf() + var contacts: List = mutableListOf() } + @Entity -open class PurchaseOrder :BaseTenantModel() { +open class PurchaseOrder : BaseTenantModel() { @DbJsonB - var products :MutableList = mutableListOf() + var products: MutableList = mutableListOf() + @ManyToOne - var vendor :Vendor? = null - var referenceQuotation :String? = "" - var totalAmount :Double = 0.0 + var vendor: Vendor? = null + var referenceQuotation: String? = "" + var totalAmount: Double = 0.0 var poNum: String = "" var poDate: LocalDate? = null var validTill: LocalDate? = null + @DbArray var tnc: List? = arrayListOf() + @DbArray var documents: List? = arrayListOf() } @@ -274,29 +279,40 @@ open class PurchaseOrder :BaseTenantModel() { enum class UOM { NOS, LTR, MTR, ALL } + @Entity -open class Product :BaseTenantModel() { +open class Product : BaseTenantModel() { + fun patchValues(updatedProduct: Product) { + this.name = updatedProduct.name + this.description = updatedProduct.description + this.hsnCode = updatedProduct.hsnCode + this.uom = updatedProduct.uom + } + var id: Long? = null - var name :String = "" - var description :String = "" - var hsnCode :String = "" + var name: String = "" + var description: String = "" + var hsnCode: String = "" + @Enumerated(EnumType.STRING) var uom: UOM? = null } @Entity -open class Quotation :BaseTenantModel() { +open class Quotation : BaseTenantModel() { @DbJsonB - var products :MutableList = mutableListOf() + var products: MutableList = mutableListOf() + @ManyToOne - var vendor :Vendor? = null - var totalAmount :Double = 0.0 + var vendor: Vendor? = null + var totalAmount: Double = 0.0 var reqForQuoteNum: String? = "" var quoteNum: String = "" var vendorQuoteNum: String? = "" var quoteDate: LocalDate? = null var validTill: LocalDate? = null + @DbArray var tnc: List? = arrayListOf() @@ -304,35 +320,40 @@ open class Quotation :BaseTenantModel() { var documents: List? = arrayListOf() } -enum class DocType{ +enum class DocType { PO, QUOTE, INVOICE, ALL } + @Entity -open class Document :BaseTenantModel() { - var name :String = "" +open class Document : BaseTenantModel() { + var name: String = "" + @Enumerated(EnumType.STRING) - var typeOfDoc :DocType? = null + var typeOfDoc: DocType? = null + //could be quoteNum, PoNum, InvoiceNum - var refId: String? = null - var description :String = "" - var url :String = "" - var docDate :LocalDate? = null - var vendor :Vendor? = null + var refIdOfDoc: Long? = null + var description: String = "" + var url: String = "" + var docDate: LocalDate? = null } -enum class RFQStatus{ +enum class RFQStatus { DELIVERED, PO, QUOTE, CANCELLED } + @Entity -open class ReqForQuote :BaseTenantModel() { +open class ReqForQuote : BaseTenantModel() { @DbArray - var potentialVendors :List? = null + var potentialVendors: List? = null + @Enumerated(EnumType.STRING) - var status :RFQStatus? = null -// @DbArray + var status: RFQStatus? = null + + // @DbArray // var docs :List? = null @DbJsonB - var products :List? = null + var products: List? = null var reqForQuoteNum: String? = null var openTill: LocalDate? = null } \ No newline at end of file diff --git a/src/main/resources/dbmigration/1.5.sql b/src/main/resources/dbmigration/1.5.sql new file mode 100644 index 0000000..d022737 --- /dev/null +++ b/src/main/resources/dbmigration/1.5.sql @@ -0,0 +1,2 @@ +-- apply alter tables +alter table document add column if not exists ref_id_of_doc bigint; diff --git a/src/main/resources/dbmigration/model/1.5.model.xml b/src/main/resources/dbmigration/model/1.5.model.xml new file mode 100644 index 0000000..695974a --- /dev/null +++ b/src/main/resources/dbmigration/model/1.5.model.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 1cbfb22..5ba8f96 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -1,4 +1,19 @@ + + api.log + + api.%d{yyyy-MM-dd}.%i.log.gz + 30 + + 100MB + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n @@ -14,5 +29,6 @@ + \ No newline at end of file