Compare commits

..

2 Commits

Author SHA1 Message Date
e94928ae7f Merge branch 'master' of https://git.basuvaraj.com/gowthaman/readymixerp_modules_api
# Conflicts:
#	api.http
#	src/main/kotlin/com/restapi/Main.kt
#	src/main/kotlin/com/restapi/controllers/Entities.kt
2024-02-08 15:14:18 +05:30
4e069e0300 fixes 2024-02-08 13:01:03 +05:30
8 changed files with 146 additions and 129 deletions

View File

@ -93,6 +93,46 @@ Authorization: {{auth-token}}
DELETE http://localhost:9001/api/vehicle/KA01HD6667
Authorization: {{auth-token}}
### get po for id
GET http://localhost:9001/api/vendor/product
Authorization: {{auth-token}}
### get product for id
GET http://localhost:9001/api/vendor/product/7
Authorization: {{auth-token}}
### get row
GET http://localhost:9001/api/vendor/product/7
Authorization: Bearer {{auth-token}}
### create product
POST http://localhost:9001/api/vendor/product
Content-Type: application/json
Authorization: {{auth-token}}
{
"name": "Shirt",
"description": "Black Shirt",
"hsnCode": "BSM1XL"
}
### update field
PATCH http://localhost:9001/api/vendor/product/11
Content-Type: application/json
Authorization: {{auth-token}}
### upate a row
PUT http://localhost:9001/api/vendor/product/11
Content-Type: application/json
Authorization: {{auth-token}}
### delete a row
DELETE http://localhost:9001/api/vendor/product/2
Authorization: {{auth-token}}
### create vendor
POST http://localhost:9001/api/vendor/
Content-Type: application/json
@ -319,38 +359,24 @@ Authorization: {{auth-token}}
"quoteFilters": {}
}
### CREATE PRODUCT
POST http://localhost:9001/api/vendor/product/create
### GET ALL PRODUCTS
POST http://localhost:9001/api/vendor/product/getAll
Content-Type: application/json
Authorization: {{auth-token}}
{
"name" : "aa",
"description": "aa",
"hsnCode" : "aa",
"uom": "NOS"
"common" : {},
"quoteFilters": {}
}
### GET ALL PRODUCTS
GET http://localhost:9001/api/vendor/product/getAll
### GET NEXT PO SEQ NUMBER
GET http://localhost:9001/api/vendor/po/next
Content-Type: application/json
Authorization: {{auth-token}}
### GET PRODUCT BY KEY
GET http://localhost:9001/api/vendor/product/of/6
Authorization: {{auth-token}}
### GET PRODUCT BY HSNCODE
DELETE http://localhost:9001/api/vendor/product/3
### GET NEXT QUOTE SEW NUMBER
GET http://localhost:9001/api/vendor/quote/next
Content-Type: application/json
Authorization: {{auth-token}}
### PRODUCT EXCEl
GET http://localhost:9001/api/vendor/product/to/excel
Authorization: {{auth-token}}
### EXCEL VALIDATE
GET http://localhost:9001/api/vendor/product/valid/excel
Authorization: {{auth-token}}
### EXCEL TO DB (IMPORT)
POST http://localhost:9001/api/vendor/product/excelToDb
Authorization: {{auth-token}}

View File

@ -6,8 +6,6 @@ import com.restapi.config.AppConfig.Companion.appConfig
import com.restapi.config.Auth.validateAuthToken
import com.restapi.controllers.*
import com.restapi.domain.DataNotFoundException
import com.restapi.domain.Product
import com.restapi.domain.Session.a
import com.restapi.domain.Session.currentTenant
import com.restapi.domain.Session.currentUser
import com.restapi.domain.Session.objectMapper
@ -19,20 +17,19 @@ import io.javalin.Javalin
import io.javalin.apibuilder.ApiBuilder.*
import io.javalin.http.ContentType
import io.javalin.http.Context
import io.javalin.http.HandlerType
import io.javalin.http.UnauthorizedResponse
import io.javalin.http.util.NaiveRateLimit
import io.javalin.http.util.RateLimitUtil
import io.javalin.json.JavalinJackson
import org.jose4j.jwt.consumer.InvalidJwtException
import org.slf4j.LoggerFactory
import java.io.InputStream
import java.security.MessageDigest
import java.time.LocalDateTime
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.jvm.optionals.getOrDefault
fun main(args: Array<String>) {
val logger = LoggerFactory.getLogger("api")
val adminRole = Role.Standard(Action.ADMIN)
@ -80,8 +77,6 @@ fun main(args: Array<String>) {
TimeUnit.MINUTES
)
if(ctx.method() == HandlerType.OPTIONS) return@before
val authToken = ctx.getAuthHeader() ?: throw UnauthorizedResponse()
@ -123,36 +118,35 @@ fun main(args: Array<String>) {
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"))))
put("/rate/{id}/{rating}", VendorCtrl::rate, Roles(Role.Explicit(listOf("ROLE_VENDOR_CREATE", "ROLE_ADMIN"))))
}
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_VENDOR_CREATE", "ROLE_ADMIN"))))
post("/getAll", PurchaseOrderCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_PO_CREATE", "ROLE_VENDOR_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", "ROLE_APPROVE"))))
put("/reject/{id}", PurchaseOrderCtrl::reject, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_APPROVE"))))
get("/refQuote/{id}", PurchaseOrderCtrl::quoteReference, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_PO_VIEW"))))
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("/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", "ROLE_VENDOR_CREATE"))))
post("/getAll", QuotationCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN", "ROLE_VENDOR_CREATE"))))
get("/{id}", QuotationCtrl::get, Roles(Role.Explicit(listOf("ROLE_QUOTE_VIEW", "ROLE_ADMIN", "ROLE_PO_CREATE", "ROLE_QUOTE_CREATE"))))
get("/po/{id}", QuotationCtrl::generatePO, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_PO_CRETE"))))
get("/rfq/{rfqNum}", QuotationCtrl::reqForQuote, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_QUOTE_VIEW"))))
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("/product") {
post("/create", ProductCtrl::create, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN"))))
get("/getAll", ProductCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN"))))
get("/of/{key}", ProductCtrl::get, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN"))))
put("/{id}", ProductCtrl::update, Roles(Role.Explicit(listOf("ROLE_PRODUCT_UPDATE", "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_DELETE", "ROLE_ADMIN"))))
get("/to/excel", ProductCtrl::prodExcel)
get("/valid/excel") { ctx -> ctx.json(ExcelRead()) }
post("/excelToDb") {ctx -> ctx.json(excelToDb())}
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("/doc"){
post("", Document::create, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE", "ROLE_ADMIN"))))
@ -163,9 +157,9 @@ fun main(args: Array<String>) {
delete("/{id}", Document::delete, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE"))))
}
path("/reqForQuote"){
post("", RequestForQuote::create, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE"))))
get("/{id}", RequestForQuote::get, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE", "ROLE_RFQ_VIEW"))))
put("/{id}", RequestForQuote::update, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE"))))
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"))))
}
}
post("/script/database/{name}", Entities::executeStoredProcedure, Roles(adminRole, Role.DbOps))

View File

@ -17,11 +17,7 @@ import com.restapi.integ.Scripting
import io.ebean.CallableSql
import io.ebean.RawSqlBuilder
import io.javalin.http.*
import org.apache.poi.ss.usermodel.WorkbookFactory
import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.sql.Types
import java.time.LocalDate
import java.time.LocalDateTime
@ -378,8 +374,19 @@ object Entities {
}
}
data class Filters(val common :CommonFilters, val custom :CustomFilters)
data class SequenceNumber(val number:String)
data class BatchPos(val pos :List<PurchaseOrder>)
object PurchaseOrderCtrl {
fun getNextNum(ctx: Context){
val prefix = "PO/"
val cnt = database.find(PurchaseOrder::class.java)
.findCount()
.toString()
.padStart(6, '0')
val seq = SequenceNumber(prefix + cnt)
ctx.json(seq).status(HttpStatus.OK)
}
fun get(ctx :Context){
val id = ctx.pathParam("id")
val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("po not found for $id")
@ -440,19 +447,25 @@ object PurchaseOrderCtrl {
data class ProductSearch(
var isSort: String? = null
)
object ProductCtrl {
fun get(ctx :Context){
val key = ctx.pathParam("key")
val product = database.find(Product::class.java, key) ?: throw NotFoundResponse("Product not found for $key")
ctx.json(product)
val id = ctx.pathParam("id")
val product = database.find(Product::class.java)
.where()
.eq("sys_pk", id.toLong())
.findOne()
?: throw NotFoundResponse("Product not found for $id")
println("Product found")
println(product)
ctx.json(product).status(HttpStatus.OK)
}
fun getAll(ctx: Context){
val productList = database.find(Product::class.java)
val productList = Session.database.find(Product::class.java)
.findList()
//.removeAt(4)
.sortedBy { it.hsnCode }
ctx.json(productList)
}
@ -464,7 +477,7 @@ object ProductCtrl {
fun delete(ctx: Context) {
val id = ctx.pathParam("id")
val product = database.deletePermanent(Product::class.java,id)
val product = database.delete(Product::class.java, id)
}
fun patch(ctx: Context) {
@ -472,44 +485,21 @@ object ProductCtrl {
}
fun update(ctx: Context) {
//have to implement
val id = ctx.pathParam("id")
}
fun prodExcel(it: Context) {
val product = database.find(Product::class.java).findList()
it.result(CreateExcel(product)).contentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
.header("Content-Disposition", "attachment; filename=\"product.xlsx\"")
}
data class ProductList(
val name: String,
val description: String,
val hsnCode: String,
val uom: String?,
)
fun excelToDb(it: Context){
val inputStream = FileInputStream("C:\\Users\\vinay\\IdeaProjects\\readymixerp_modules_api_git\\Untitled 1.xlsx")
val workbook = WorkbookFactory.create(inputStream)
val workSheet = workbook.getSheetAt(0)
val dataList = mutableListOf<ProductList>()
for (row in workSheet) {
val cell1Value = row.getCell(0).stringCellValue
val cell2Value = row.getCell(1).stringCellValue
val cell3Value = row.getCell(2).stringCellValue
val cell4Value = row.getCell(3).stringCellValue
val data = ProductList(cell1Value, cell2Value, cell3Value, cell4Value)
dataList.add(data)
}
database.saveAll(dataList)
}
}
object QuotationCtrl {
fun getNextNum(ctx: Context){
val prefix = "QUOTE/"
val cnt = database.find(Quotation::class.java)
.findCount()
.toString()
.padStart(6, '0')
val seq = SequenceNumber(prefix + cnt)
ctx.json(seq).status(HttpStatus.OK)
}
fun get(ctx :Context){
val id = ctx.pathParam("id")
val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for $id")
@ -525,27 +515,8 @@ object QuotationCtrl {
fun create(ctx :Context){
val quote = ctx.bodyAsClass<Quotation>()
//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.status(HttpStatus.CREATED)
ctx.json(quote)
}else {
ctx.status(HttpStatus.BAD_REQUEST)
ctx.result("request for quote closed")
}
}else {
throw NotFoundResponse("request for quote not found for this quotation")
}
database.save(quote)
ctx.json(quote).status(HttpStatus.CREATED)
}
fun createBatch(ctx :Context){
val quotes = ctx.bodyAsClass<List<Quotation>>()
@ -713,4 +684,4 @@ object RequestForQuote {
//shuld we compare the new body fields with preexisting ones and prepare a sql query to update those fields??
}
}
}

View File

@ -167,7 +167,7 @@ fun ExportQuotations(quotes :List<Quotation>) {
row.createCell(i++).setCellValue(quote.reqForQuoteNum)
row.createCell(i++).setCellValue(quote.totalAmount)
row.createCell(i++).setCellValue(quote.tnc.joinToString(";"))
row.createCell(i++).setCellValue(quote.tnc?.joinToString(";"))
}
}
}

View File

@ -66,9 +66,12 @@ data class VendorFilters (
) :CustomFilters
fun<T> applyVendorHelper(q :io.ebean.ExpressionList<T>, vids :List<Long>?) {
if (vids.isNullOrEmpty()) return
q.apply {
q.`in`("vendor", vids)
}
// q.apply {
// q.`in`("vendor", vids)
// }
// println(vids)
// println(vids[0])
q.eq("vendor_sys_pk", vids[0])
}
fun<T> applySortHelper(q :io.ebean.ExpressionList<T>, sortBy :String, asc :Boolean) {
if(sortBy == IGNORE) return;
@ -93,6 +96,7 @@ fun searchQuotes(commonFilters: CommonFilters, quoteFilters: QuoteFilters) : Lis
.ge("totalAmount", quoteFilters.totalAmountExceeds)
.le("totalAmount", quoteFilters.totalAmountLessThan)
.ilike("quoteNum", "%" + quoteFilters.quoteNumLike + "%")
applyFromToHelper(q, commonFilters.fromDate, commonFilters.toDate, "quoteDate")
applyVendorHelper(q, commonFilters.vendor)
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()
@ -132,6 +136,7 @@ fun searchPos(commonFilters: CommonFilters, poFilters: POFilters?) : List<Purcha
.le("validTill", poFilters.validBefore)
.ilike("poNum", "%" + poFilters.poNumLike + "%")
.ilike("referenceQuotation", "%" + poFilters.refQuotation + "%")
applyFromToHelper(q, commonFilters.fromDate, commonFilters.toDate, "poDate")
applyVendorHelper(q, commonFilters.vendor)
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()

View File

@ -269,7 +269,7 @@ open class PurchaseOrder :BaseTenantModel() {
@DbArray
var tnc: List<String>? = arrayListOf()
@DbArray
var documents: MutableList<Long>? = arrayListOf()
var documents: List<String>? = arrayListOf()
}
enum class UOM {
@ -296,13 +296,14 @@ open class Quotation :BaseTenantModel() {
var reqForQuoteNum: String? = ""
var quoteNum: String = ""
var vendorQuoteNum: String? = ""
var quoteDate: LocalDate? = null
var validTill: LocalDate? = null
@DbArray
var tnc: List<String> = arrayListOf()
var tnc: List<String>? = arrayListOf()
@DbArray
var documents: MutableList<Long> = arrayListOf()
var documents: List<String>? = arrayListOf()
}
enum class DocType{

View File

@ -0,0 +1,8 @@
-- apply alter tables
alter table purchase_order alter column tnc drop not null;
alter table purchase_order alter column documents type varchar[] using documents::varchar[];
alter table purchase_order alter column documents drop not null;
alter table quotation alter column tnc drop not null;
alter table quotation alter column documents type varchar[] using documents::varchar[];
alter table quotation alter column documents drop not null;
alter table quotation add column if not exists vendor_quote_num varchar(255);

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<alterColumn columnName="tnc" tableName="purchase_order" currentType="varchar[]" notnull="false" currentNotnull="true"/>
<alterColumn columnName="documents" tableName="purchase_order" type="varchar[]" currentType="bigint[]" notnull="false" currentNotnull="true"/>
<alterColumn columnName="tnc" tableName="quotation" currentType="varchar[]" notnull="false" currentNotnull="true"/>
<alterColumn columnName="documents" tableName="quotation" type="varchar[]" currentType="bigint[]" notnull="false" currentNotnull="true"/>
<addColumn tableName="quotation">
<column name="vendor_quote_num" type="varchar"/>
</addColumn>
</changeSet>
</migration>