neary finished on add contract

This commit is contained in:
Paul Wilde 2023-01-30 12:48:31 +00:00
parent 494c25e8ec
commit 2dfd7007c9
8 changed files with 323 additions and 122 deletions

View file

@ -21,6 +21,7 @@
"vue-datepicker": "^1.3.0",
"vue-meta": "^2.4.0",
"vue-router": "^4.0.3",
"vue-splash": "^1.2.1",
"vue-virtual-scroller": "^2.0.0-beta.7",
"vue3-html2pdf": "^1.1.2",
"vue3-print-nb": "^0.1.4",

View file

@ -1,12 +1,40 @@
<template>
<CMCApp />
<CMCApp :class="{ fadein : !isLoading }" v-if="!isLoading" />
<LoadingScreen :isLoading="isLoading" />
</template>
<script>
import CMCApp from './CMCApp.vue'
import LoadingScreen from "./components/LoadingScreen.vue"
export default {
data(){
return {
isLoading: true
}
},
components: {
CMCApp
CMCApp,
LoadingScreen
},
mounted(){
setTimeout(() => {
this.isLoading = false;
},3000);
}
}
</script>
<style>
.fadein {
animation: fadein 1s forwards;
}
@keyframes fadein {
from {
opacity:0;
visibility:hidden;
}
to {
opacity:1;
visibility:visible;
}
}
</style>

View file

@ -1,6 +1,12 @@
<script>
import moment from 'moment'
import axios from 'axios'
export default {
data() {
return {
customer_list: []
}
},
methods:{
formatDate(d,f) {
return moment(String(d)).format(f)
@ -26,6 +32,26 @@ export default {
minute: '2-digit',
second: '2-digit'})
},
async getCustomerList(name) {
console.log("searching customers...")
if (this.customer_list.length == 0) {
console.log("getting new customers...")
let url = this.$api_url + "/customers/full_list"
axios.get(url)
.then(resp => {
this.customer_list = resp.data
console.log(this.customer_list)
return this.customer_list.filter(x => {
x.name.contains(name) || x.acc_no.contains(name)
})
})
.catch(err => {
console.log(err)
})
} else {
return this.customer_list
}
}
}
}
</script>

View file

@ -0,0 +1,40 @@
<template>
<div :class="{ loader: true, fadeout: !isLoading }">
Loading ...
</div>
</template>
<script>
export default {
name: "LoadingScreen",
props: ["isLoading"]
};
</script>
<style>
.loader {
background-color: lightyellow;
bottom: 0;
color: black;
display: block;
font-size: 16px;
left: 0;
overflow: hidden;
padding-top: 10vh;
position: fixed;
right: 0;
text-align: center;
top: 0;
}
.fadeout {
animation: fadeout 1s forwards;
}
@keyframes fadeout {
to {
opacity: 0;
visibility: hidden;
}
}
</style>

View file

@ -0,0 +1,25 @@
<script>
export default class Contract {
no = "";
customer = {
id: "",
acc_no: "",
name: "",
short_name: "",
at_risk: false,
address: {
}
};
terms = "";
products = [];
start_date = new Date();
finish_date = new Date();
agree_date = "";
tonnage_per_month = 1;
total_tonnage = 1;
comments = "";
office_comments = "";
active = true;
isNew = true;
}
</script>

View file

@ -1,10 +1,25 @@
<template>
<v-card title="Edit Contract" :subtitle="'Contract : ' + contract.no">
<v-card :title="title" :subtitle="'Contract : ' + contract.no">
{{ contract }}
<v-card-text>
<v-container>
<v-row>
<v-col cols="6">
<v-text-field label="Customer" v-model="contract.customer.name" readonly></v-text-field>
<v-autocomplete
label="Customer"
v-model="contract.customer.acc_no"
v-model:search="customer_search"
:loading="customers_loading"
:items="customers"
cache-items
hide-no-data
hide-details
solo-inverted
no-data-text="No Customers Found"
item-title="full_title"
item-value="acc_no"
:readonly="!contract.isNew">
</v-autocomplete>
<v-text-field type="number" label="Tonnage Per Month" v-model="contract.tonnage_per_month"></v-text-field>
</v-col>
<v-col cols="6">
@ -62,9 +77,12 @@
</v-container>
</v-card-text>
<v-card-actions>
<v-btn color="red-darken-1"
<v-btn v-if="!contract.isNew" color="red-darken-1"
variant="text"
@click="saveContract(selected_contract)">Save</v-btn>
<v-btn v-if="contract.isNew" color="red-darken-1"
variant="text"
@click="saveContract(selected_contract)">Add</v-btn>
<v-spacer></v-spacer>
<v-btn color="blue-darken-1"
variant="text"
@ -75,28 +93,10 @@
<script>
import axios from 'axios'
import DatePicker from '@vuepic/vue-datepicker'
import methods from '@/CommonMethods.vue'
export default {
props: {
setcontract: {
no: Number,
customer: {
acc_no: String,
name: String,
at_risk: Boolean,
},
products: [{
code: String,
name: String,
price: Number,
}],
start_date: String,
finish_date: String,
agree_date: String,
tonnage_per_month: Number,
comments: String,
office_comments: String,
active: Boolean
}
setcontract: {}
},
components: {
DatePicker
@ -109,8 +109,14 @@ export default {
if (val && val.length > 1) {
this.searchProducts(val)
}
},
customer_search(val) {
if (val && val.length > 2) {
this.searchCustomers(val)
}
}
},
mixins: [methods],
data() {
return {
contract: this.setcontract,
@ -119,6 +125,18 @@ export default {
product_search: null,
products_loading: false,
products: [],
customer_search: null,
customers_loading: false,
customers: [],
}
},
computed: {
title() {
if ( this.contract.isNew ) {
return "New Contract"
} else {
return "Edit Contract"
}
}
},
methods: {
@ -128,8 +146,9 @@ export default {
async saveContract(){
this.saving = true
let url = this.$api_url + "/customers/contracts/" + this.contract.no + "/save"
console.log("Saving Contract : ", this.contract.no)
console.log(this.contract)
if (this.contract.isNew) {
url = this.$api_url + "/customers/contracts/add"
}
axios.post(url, {
contract: this.contract
}).then(resp => {
@ -141,13 +160,22 @@ export default {
this.saving = false
})
},
async searchCustomers(name) {
let url = this.$api_url + "/customers/search/" + name
axios.get(url)
.then(resp => {
this.customers = resp.data
})
.catch(err => {
console.log(err)
})
},
searchProducts(code) {
let url = this.$api_url + "/products/search/" + code
console.log(url)
axios.get(url)
.then(resp => {
console.log(resp)
this.products = resp.data
this.products = resp.data
})
.catch(err => {
console.log(err)

View file

@ -17,104 +17,110 @@
density="compact"
append-inner-icon="mdi-magnify"></v-text-field>
</v-responsive>
<v-dialog v-model="showDialog">
</v-dialog>
<v-row>
<v-col cols="8" xs="12" sm="12" md="8">
<v-progress-linear indeterminate color="blue" :active="loading"></v-progress-linear>
<RecycleScroller class="scroller"
:items="filteredContracts"
:item-size="130"
v-slot="{ item }"
key-field="no"
>
<v-row :class="[{inactive : !item.active}]" class="item">
<v-col cols="4" >
<h3>Contract : {{ item.no }}</h3>
{{ item.customer.acc_no }} - {{ item.customer.name }}
<v-switch v-model="item.active" color="green" @change="setContractInactive(item)" label="Active"></v-switch>
</v-col>
<v-col >
<template v-for="p in item.products" :key="p.code">
<span v-if="p.code != ''">
{{ p.code }} @ {{ p.price }}<br/>
</span>
</template>
</v-col>
<v-col >
<v-icon title="Start">mdi-play</v-icon>: {{ formatDate(item.start_date,"DD/MM/YYYY") }}<br/>
<v-icon title="Finish">mdi-flag-checkered</v-icon>: {{ formatDate(item.finish_date,"DD/MM/YYYY") }}<br/>
<v-icon title="Duration">mdi-clock</v-icon>: {{ item.duration }} months
</v-col>
<v-col>
{{ item.tonnage_per_month }} per month<br/>
= {{ formatNumber(item.tonnage_per_month * item.duration,2) }} total<br/>
= {{ formatNumber(item.tonnage_per_month * item.remaining_duration,2) }} remaining<br/>
</v-col>
<v-col>
<v-row>
<v-col cols="12">
<v-btn color="info">
More
<v-overlay activator="parent" class="align-center justify-center">
<v-card title="Info" width="600">
<v-card-subtitle>Comments</v-card-subtitle>
<v-card-text>{{ item.comments}} </v-card-text>
<v-card-subtitle>Office</v-card-subtitle>
<v-card-text>{{ item.office_comments}}</v-card-text>
<v-card-subtitle>Agreed</v-card-subtitle>
<v-card-text>{{ formatDate(item.agree_date,"DD/MM/YYYY") }}</v-card-text>
<v-card-subtitle>Products</v-card-subtitle>
<v-card-text>
<template v-for="p in item.products" :key="p.code">
<span v-if="p.code != ''">
{{ p.code }} - {{ p.name }} @ {{ p.price }}<br/>
</span>
</template>
</v-card-text>
<v-card-actions>
<v-btn color="info"
target="blank"
@click="getContractPrint(item.no)"
class="ma-2 pa-2"
:loading="item.multiloading"
>
Multi
</v-btn>
<v-btn color="warning"
v-if="site_info.features.editcontract"
@click="showEditContract()"
>
Add
</v-btn>
<v-dialog v-model="showDialog">
</v-dialog>
<v-row>
<v-col cols="8" xs="12" sm="12" md="8">
<v-progress-linear indeterminate color="blue" :active="loading"></v-progress-linear>
<RecycleScroller class="scroller"
:items="filteredContracts"
:item-size="130"
v-slot="{ item }"
key-field="no"
>
<v-row :class="[{inactive : !item.active}]" class="item">
<v-col cols="4" >
<h3>Contract : {{ item.no }}</h3>
{{ item.customer.acc_no }} - {{ item.customer.name }}
<v-switch v-model="item.active" color="green" @change="setContractInactive(item)" label="Active"></v-switch>
</v-col>
<v-col >
<template v-for="p in item.products" :key="p.code">
<span v-if="p.code != ''">
{{ p.code }} @ {{ p.price }}<br/>
</span>
</template>
</v-col>
<v-col >
<v-icon title="Start">mdi-play</v-icon>: {{ formatDate(item.start_date,"DD/MM/YYYY") }}<br/>
<v-icon title="Finish">mdi-flag-checkered</v-icon>: {{ formatDate(item.finish_date,"DD/MM/YYYY") }}<br/>
<v-icon title="Duration">mdi-clock</v-icon>: {{ item.duration }} months
</v-col>
<v-col>
{{ item.tonnage_per_month }} per month<br/>
= {{ formatNumber(item.tonnage_per_month * item.duration,2) }} total<br/>
= {{ formatNumber(item.tonnage_per_month * item.remaining_duration,2) }} remaining<br/>
</v-col>
<v-col>
<v-row>
<v-col cols="12">
<v-btn color="info">
More
<v-overlay activator="parent" class="align-center justify-center">
<v-card title="Info" width="600">
<v-card-subtitle>Comments</v-card-subtitle>
<v-card-text>{{ item.comments}} </v-card-text>
<v-card-subtitle>Office</v-card-subtitle>
<v-card-text>{{ item.office_comments}}</v-card-text>
<v-card-subtitle>Agreed</v-card-subtitle>
<v-card-text>{{ formatDate(item.agree_date,"DD/MM/YYYY") }}</v-card-text>
<v-card-subtitle>Products</v-card-subtitle>
<v-card-text>
<template v-for="p in item.products" :key="p.code">
<span v-if="p.code != ''">
{{ p.code }} - {{ p.name }} @ {{ p.price }}<br/>
</span>
</template>
</v-card-text>
<v-card-actions>
<v-btn color="info"
target="blank"
@click="getContractPrint(item.no,true)"
:loading="item.totalloading"
@click="getContractPrint(item.no)"
class="ma-2 pa-2"
:loading="item.multiloading"
>
Total
Multi
</v-btn>
<v-btn color="warning"
v-if="site_info.features.editcontract"
@click="showEditContract(item)"
<v-btn color="info"
target="blank"
@click="getContractPrint(item.no,true)"
:loading="item.totalloading"
class="ma-2 pa-2"
>
Edit
Total
</v-btn>
</v-card-actions>
</v-card>
</v-overlay>
</v-btn>
</v-col>
<v-col cols="12">
<v-btn color="warning"
v-if="site_info.features.editcontract"
@click="showEditContract(item)"
>
Edit
</v-btn>
</v-col>
</v-row>
</v-col>
</v-row>
</RecycleScroller>
</v-col>
</v-row>
<v-btn color="warning"
v-if="site_info.features.editcontract"
@click="showEditContract(item)"
>
Edit
</v-btn>
</v-card-actions>
</v-card>
</v-overlay>
</v-btn>
</v-col>
<v-col cols="12">
<v-btn color="warning"
v-if="site_info.features.editcontract"
@click="showEditContract(item)"
>
Edit
</v-btn>
</v-col>
</v-row>
</v-col>
</v-row>
</RecycleScroller>
</v-col>
</v-row>
</v-window-item>
<v-window-item value="edit">
<ContractEdit ref="edit" :setcontract="selected_contract" @closetab="tab = 'list'" @contractupdate="contractUpdated"/>
@ -128,6 +134,7 @@
import ContractEdit from './ContractEdit.vue';
import ContractMulti from './ContractMulti.vue';
import methods from '@/CommonMethods.vue'
import ContractType from '@/types/ContractType.vue';
import axios from 'axios'
export default {
props: {
@ -185,8 +192,11 @@ export default {
mixins: [methods],
methods: {
async showEditContract(contract) {
this.selected_contract = contract
//this.selected_contract = contract
if ( contract != undefined ) {
this.selected_contract = contract
} else {
this.selected_contract = new ContractType()
}
this.tab = "edit"
this.edit = true
},

View file

@ -294,6 +294,11 @@
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.20.7.tgz#66fe23b3c8569220817d5feb8b9dcdc95bb4f71b"
integrity sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==
"@babel/parser@^7.18.4":
version "7.20.13"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.13.tgz#ddf1eb5a813588d2fb1692b70c6fce75b945c088"
integrity sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
version "7.18.6"
resolved "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
@ -1561,6 +1566,15 @@
"@vue/compiler-core" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-sfc@2.7.14":
version "2.7.14"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz#3446fd2fbb670d709277fc3ffa88efc5e10284fd"
integrity sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==
dependencies:
"@babel/parser" "^7.18.4"
postcss "^8.4.14"
source-map "^0.6.1"
"@vue/compiler-sfc@3.2.45", "@vue/compiler-sfc@^3.0.11":
version "3.2.45"
resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz#7f7989cc04ec9e7c55acd406827a2c4e96872c70"
@ -2768,6 +2782,11 @@ csstype@^2.6.8:
resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e"
integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==
csstype@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@ -5295,6 +5314,15 @@ postcss@^8.1.10, postcss@^8.2.6, postcss@^8.3.5, postcss@^8.4.19:
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.4.14:
version "8.4.21"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4"
integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@ -6490,6 +6518,13 @@ vue-router@^4.0.3:
dependencies:
"@vue/devtools-api" "^6.4.5"
vue-splash@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/vue-splash/-/vue-splash-1.2.1.tgz#d9f4857c39195639545c93a83551c2b323f4be99"
integrity sha512-e943XhOtvAZK/Vr1DNAHaD4/A6mQBvubClUN2HozIw+qKktT8PZwOo87LL09xm1oPUee7dS8/XNEDAMGMObacg==
dependencies:
vue "^2.6.11"
vue-style-loader@^4.1.0, vue-style-loader@^4.1.3:
version "4.1.3"
resolved "https://registry.npmmirror.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz#6d55863a51fa757ab24e89d9371465072aa7bc35"
@ -6527,6 +6562,14 @@ vue3-print-nb@^0.1.4:
dependencies:
vue "^3.0.5"
vue@^2.6.11:
version "2.7.14"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.7.14.tgz#3743dcd248fd3a34d421ae456b864a0246bafb17"
integrity sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==
dependencies:
"@vue/compiler-sfc" "2.7.14"
csstype "^3.1.0"
vue@^3.0.5, vue@^3.2.13:
version "3.2.45"
resolved "https://registry.npmmirror.com/vue/-/vue-3.2.45.tgz#94a116784447eb7dbd892167784619fef379b3c8"