From 20f6abf3b70dbe554dfcd0ed0db6a4d90eccb5c9 Mon Sep 17 00:00:00 2001 From: arsalan Date: Fri, 19 Jan 2024 09:51:58 +0530 Subject: [PATCH] add endpoints --- src/main/kotlin/com/restapi/Main.kt | 39 +++- .../com/restapi/controllers/Entities.kt | 198 +++++++++++++++++- src/main/kotlin/com/restapi/domain/models.kt | 25 ++- 3 files changed, 255 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/com/restapi/Main.kt b/src/main/kotlin/com/restapi/Main.kt index c63c188..2389d6a 100644 --- a/src/main/kotlin/com/restapi/Main.kt +++ b/src/main/kotlin/com/restapi/Main.kt @@ -4,8 +4,7 @@ import com.fasterxml.jackson.databind.JsonMappingException import com.restapi.config.* import com.restapi.config.AppConfig.Companion.appConfig import com.restapi.config.Auth.validateAuthToken -import com.restapi.controllers.Entities -import com.restapi.controllers.PurchaseOrder +import com.restapi.controllers.* import com.restapi.domain.DataNotFoundException import com.restapi.domain.Session import com.restapi.domain.Session.currentTenant @@ -114,9 +113,45 @@ fun main(args: Array) { } path("/vendor"){ + path("/"){ + post("", Vendor::create, Roles(Role.Explicit(listOf("ROLE_VENDOR_CREATE", "ROLE_ADMIN")))) + get("", Vendor::get, Roles(Role.Explicit(listOf("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE", "ROLE_ADMIN")))) + get("quotes/{id}", Vendor::getQuotes, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE", "ROLE_VENDOR_VIEW")))) + get("pos/{id}", Vendor::getPos, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_PO_VIEW", "ROLE_PO_CREATE`")))) + put("/rate/{id}/{rating}", Vendor::rate, Roles(Role.Explicit(listOf("ROLE_VENDOR_CREATE")))) + } path("/po"){ post("", PurchaseOrder::create, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_ADMIN")))) get("/{id}", PurchaseOrder::get, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_QUOTE_CREATE")))) + put("/approve/{id}", PurchaseOrder::approve, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_APPROVE")))) + put("/reject/{id}", PurchaseOrder::reject, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_APPROVE")))) + get("/refQuote/{id}", PurchaseOrder::quoteReference, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_PO_VIEW")))) + } + path("/quote"){ + post("", Quotation::create, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN")))) + get("/{id}", Quotation::get, Roles(Role.Explicit(listOf("ROLE_QUOTE_VIEW", "ROLE_ADMIN", "ROLE_PO_CREATE", "ROLE_QUOTE_CREATE")))) + get("/po/{id}", Quotation::generatePO, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_PO_CRETE")))) + get("/rfq/{rfqNum}", Quotation::reqForQuote, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_QUOTE_VIEW")))) + delete("/{id}", Quotation::delete, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN")))) + } + path("/product"){ + post("", Product::create, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN")))) + get("/{id}", Product::get, Roles(Role.Explicit(listOf("ROLE_DOC_VIEW", "ROLE_ADMIN", "ROLE_PRODUCT_CREATE")))) + delete("{id}", Product::delete, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN")))) + get("/doc/{id}", Product::getDoc, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_VIEW_DOC")))) + } + path("/doc"){ + post("", Document::create, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE", "ROLE_ADMIN")))) + //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")))) + } + path("/reqForQuote"){ + post("", ReqForQuote::create, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE")))) + get("/{id}", ReqForQuote::get, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE", "ROLE_RFQ_VIEW")))) + put("/{id}", ReqForQuote::update, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE")))) } } post("/script/database/{name}", Entities::executeStoredProcedure, Roles(adminRole, Role.DbOps)) diff --git a/src/main/kotlin/com/restapi/controllers/Entities.kt b/src/main/kotlin/com/restapi/controllers/Entities.kt index 746319c..1aff54e 100644 --- a/src/main/kotlin/com/restapi/controllers/Entities.kt +++ b/src/main/kotlin/com/restapi/controllers/Entities.kt @@ -7,16 +7,15 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.restapi.domain.* 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 -import io.javalin.http.BadRequestResponse -import io.javalin.http.Context -import io.javalin.http.NotFoundResponse -import io.javalin.http.bodyAsClass +import io.javalin.http.* import org.slf4j.LoggerFactory import java.sql.Types import java.time.LocalDate @@ -384,5 +383,196 @@ object PurchaseOrder { fun create(ctx :Context){ val po = ctx.bodyAsClass() database.save(po) + ctx.result("po created") } + 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 + po.save() + ctx.result("po with id $id approved") + //reject all other pos pertaining to the same tx ?? + } + 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.result("po with id $id rejected") + } + 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) + .where() + .eq("referenceQuotation", id) + ?: throw NotFoundResponse("reference quotation not found for po $id") + ctx.json(quote) + } +} + +object Quotation { + fun get(ctx :Context){ + val id = ctx.pathParam("id") + val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for $id") + ctx.json(quote) + } + fun create(ctx :Context){ + val quote = ctx.bodyAsClass() + //we have to check if the quotation created date is below the expiry of rfq + val rfq = database.find(com.restapi.domain.ReqForQuote::class.java) + .where() + .eq("reqForQuoteNum", quote.reqForQuoteNum) + .findOne() + if(rfq != null){ + //compare dates + if(quote.quoteDate!! <= rfq.openTill) { + //valid + database.save(quote) + ctx.result("quote created") + }else { + ctx.result("request for quote closed") + } + }else { + throw NotFoundResponse("request for quote not found for this quotation") + } + + } + 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") + quote.delete() + ctx.result("quote with $id deleted") + } + 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")) + val rfq = database.find(ReqForQuote::class.java) + .where() + .eq("reqForQuoteNum", reqForQuoteNum) + ?: throw NotFoundResponse("request for quote not found for this quotation") + ctx.json(rfq) + } +} +object Product { + fun get(ctx :Context){ + val id = ctx.pathParam("id") + val product = database.find(Product::class.java, id) ?: throw NotFoundResponse("product nor found for id $id") + ctx.json(product) + } + fun create(ctx :Context){ + val product = ctx.bodyAsClass() + database.save(product) + ctx.result("product created") + } + fun update(ctx :Context){ + + } + fun delete(ctx: Context){ + val id = ctx.pathParam(("id")) + val product = database.find(Product::class.java, id) ?:throw NotFoundResponse("product not found for id $id") + //product.delete() + ctx.result("product with id $id deleted") + } + fun getDoc(ctx :Context){ + + } +} +object Document { + 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.json(doc) + } + fun create(ctx :Context){ + val doc = ctx.bodyAsClass() + database.save(doc) + ctx.result("doc created") + } + fun print(ctx :Context){ + //would be handled in the frontend ?? + } + 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") + //doc.delete() + ctx.result("document deleted") + } + 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) + ?: throw NotFoundResponse("no doc found for refId $refId") + ctx.json(doc) + } + +} +object 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.json(vendor) + } + fun create(ctx :Context){ + val vendor = ctx.bodyAsClass() + database.save(vendor) + ctx.result("vendor created") + } + fun update(ctx :Context){ + + } + fun delete(ctx :Context){ + + } + fun getQuotes(ctx :Context){ + val id = ctx.pathParam("id") + val quotes = database.find(Quotation::class.java) + .where() + .eq("vendor", id) + .findList() + ctx.json(quotes) + } + fun getPos(ctx :Context){ + val id = ctx.pathParam("id") + val pos = database.find(PurchaseOrder::class.java) + .where() + .eq("vendor", id) + .findList() + ctx.json(pos) + } + 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.result("rating changed") + } +} +object ReqForQuote { + fun create(ctx :Context) { + val rfq = ctx.bodyAsClass() + database.save(rfq) + //ctx.result("request for quote created") + //ctx.json(rfq) + //ctx.status(HttpStatus.CREATED) + //ctx.json("asss") + } + fun get(ctx :Context){ + val id = ctx.pathParam("id") + val rfq = database.find(com.restapi.domain.ReqForQuote::class.java, id) ?: throw NotFoundResponse("request for quote not found for id $id") + ctx.json(rfq) + } + fun update(ctx :Context){ + //shuld we compare the new body fields with preexisting ones and prepare a sql query to update those fields?? + + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/restapi/domain/models.kt b/src/main/kotlin/com/restapi/domain/models.kt index 10a190b..dab5b6b 100644 --- a/src/main/kotlin/com/restapi/domain/models.kt +++ b/src/main/kotlin/com/restapi/domain/models.kt @@ -290,6 +290,7 @@ open class Quotation :BaseTenantModel() { var vendor :Vendor? = null var totalAmount :Int = 0 + var reqForQuoteNum: String = "" var quoteNum: String = "" var quoteDate: LocalDate? = null var validTill: LocalDate? = null @@ -300,10 +301,32 @@ open class Quotation :BaseTenantModel() { var documents: MutableList = arrayListOf() } +enum class DOCTYPE{ + PO, QUOTE, INVOICE +} @Entity open class Document :BaseTenantModel() { var name :String = "" - var typeOfDoc :String = "" + @Enumerated(EnumType.STRING) + var typeOfDoc :DOCTYPE? = null + var refId: Long? = null var description :String = "" var url :String = "" +} + +enum class RFQStatus{ + DELIVERED, PO, QUOTE, CANCELLED +} +@Entity +open class ReqForQuote :BaseTenantModel() { + @DbArray + var potentialVendors :List? = null + @Enumerated(EnumType.STRING) + var status :RFQStatus? = null + @DbArray + var docs :List? = null + @DbJsonB + var products :List? = null + var reqForQuoteNum: String? = null + var openTill: LocalDate? = null } \ No newline at end of file