Skip to content

Commit

Permalink
Merge pull request #2002 from slntopp/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
SazukinPavel authored Feb 12, 2025
2 parents 195f5c1 + ed9abc7 commit 23c5f0a
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 31 deletions.
2 changes: 1 addition & 1 deletion admin-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"jodit-vue": "^2.6.0",
"js-cookie": "^3.0.5",
"json-schema": "^0.4.0",
"nocloud-proto": "https://github.com/slntopp/nocloud-proto#36f115ce6bf0d0c2615c2c00e970df0c7e450882",
"nocloud-proto": "https://github.com/slntopp/nocloud-proto#78355039f2b5400d80d26b6006bc659c294212db",
"nocloud-ui": "^1.0.16",
"nocloudjsrest": "^1.5.17",
"nth-check": "^2.1.1",
Expand Down
186 changes: 186 additions & 0 deletions admin-ui/src/components/ServicesProvider/suspend-rules.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<template>
<div class="pa-5">
<div class="d-flex align-center">
<v-card-title>Rules enabled</v-card-title>
<v-switch v-model="isRulesEnabled"></v-switch>
</div>

<v-form ref="suspendRulesForm">
<div v-for="day in dayOfWeeks" :key="day">
<v-card-title
>{{ day }}
<v-btn @click="addNewIn(day)" class="mr-2" icon>
<v-icon>mdi-plus</v-icon>
</v-btn></v-card-title
>

<v-row
v-for="(rule, index) in suspendRules[day]"
:key="index"
class="rule-row"
>
<div class="field">
<span>UTC Start time:</span>
<v-text-field :rules="timeRule" v-model="rule.startTime" />
</div>
<div class="field">
<span>Local Start time:</span>
<v-text-field
disabled
readonly
:value="formatTimeFromUtc(rule.startTime)"
/>
</div>
<div class="field">
<span>UTC End time:</span>
<v-text-field :rules="timeRule" v-model="rule.endTime" />
</div>
<div class="field">
<span>Local End time:</span>
<v-text-field
disabled
readonly
:value="formatTimeFromUtc(rule.endTime)"
/>
</div>

<div class="d-flex justify-center align-center">
<v-btn @click="deleteRangeFromDay(day, index)" class="mr-2" icon>
<v-icon>mdi-delete</v-icon>
</v-btn>
</div>
</v-row>
</div>
</v-form>

<div class="d-flex justify-end">
<v-btn @click="save" :loading="isSaveLoading">Save</v-btn>
</div>
</div>
</template>

<script setup>
import { DayOfWeek } from "nocloud-proto/proto/es/services_providers/services_providers_pb";
import { onMounted, ref, toRefs } from "vue";
import { useStore } from "@/store";
import api from "@/api";
const dayOfWeeks = Object.keys(DayOfWeek).filter((v) => !+v && +v !== 0);
const props = defineProps(["template"]);
const { template } = toRefs(props);
const store = useStore();
const suspendRules = ref({});
const isRulesEnabled = ref(false);
const isSaveLoading = ref(false);
const suspendRulesForm = ref();
const timeRule = [(v) => !!isTime(v) || "Not valid time"];
onMounted(() => {
dayOfWeeks.forEach((day) => (suspendRules.value[day] = []));
setTemplateRules();
isRulesEnabled.value = !!template.value?.suspendRules?.enabled;
});
function formatTimeFromUtc(time) {
if (!isTime(time)) {
return "-";
}
const nowDate = new Date().toUTCString();
const oldTime = /[0-9]{2}:[0-9]{2}/.exec(nowDate)[0];
var newDate = new Date(Date.parse(nowDate.replace(oldTime, time)));
return /[0-9]{2}:[0-9]{2}/.exec(newDate)[0];
}
function isTime(value) {
return /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test(value);
}
const setTemplateRules = () => {
template.value.suspendRules.schedules.map((shedule) => {
suspendRules.value[shedule.day] = shedule.allowedSuspendTime.map(
(range) =>
({
startTime: range.startTime,
endTime: range.endTime,
} || [])
);
});
suspendRules.value = { ...suspendRules.value };
};
const addNewIn = (day) => {
suspendRules.value[day].push({
endTime: "00:00",
startTime: "00:00",
});
suspendRules.value = { ...suspendRules.value };
};
const deleteRangeFromDay = (day, index) => {
suspendRules.value[day] = suspendRules.value[day].filter(
(_, i) => i !== index
);
suspendRules.value = { ...suspendRules.value };
};
const save = async () => {
if (!suspendRulesForm.value.validate()) {
store.commit("snackbar/showSnackbarError", {
message: "Rules not valid!!!",
});
return;
}
isSaveLoading.value = true;
try {
const newSuspendRules = {};
newSuspendRules.enabled = isRulesEnabled.value;
newSuspendRules.schedules = [];
Object.keys(suspendRules.value).map((day) => {
newSuspendRules.schedules.push({
day,
allowedSuspendTime: suspendRules.value[day],
});
});
await api.servicesProviders.update(template.value.uuid, {
...template.value,
suspendRules: newSuspendRules,
});
store.commit("snackbar/showSnackbarSuccess", {
message: "Done",
});
} catch {
store.commit("snackbar/showSnackbarError", {
message: "Error while try update suspend rules",
});
} finally {
isSaveLoading.value = false;
}
};
</script>
<style scoped lang="scss">
.rule-row {
.field {
margin: 0px 20px;
display: flex;
align-items: center;
span {
margin-right: 10px;
}
div {
max-width: 75px;
}
}
}
</style>
8 changes: 4 additions & 4 deletions admin-ui/src/components/account/info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
</v-btn>
</confirm-dialog>
</hint-btn>
<hint-btn hint="Create transaction/invoice">
<v-chip @click="openTransaction" class="ma-1" color="primary" outlined
<hint-btn hint="Create invoice">
<v-chip @click="openInvoice" class="ma-1" color="primary" outlined
>Balance: {{ account.balance?.toFixed(2) || 0 }}
{{ account.currency?.code }}</v-chip
>
Expand Down Expand Up @@ -438,9 +438,9 @@ export default {
this.isChangeRegularPaymentLoading = false;
}
},
openTransaction() {
openInvoice() {
this.$router.push({
name: "Transactions create",
name: "Invoice create",
query: { account: this.account.uuid },
});
},
Expand Down
22 changes: 15 additions & 7 deletions admin-ui/src/components/invoiceItemsTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@
</template>

<template v-if="showDelete" v-slot:[`item.total`]="{ item }">
<span>{{ (item.price * item.amount || 0).toFixed(2) }}</span>
<span>{{
[
(item.price * item.amount || 0).toFixed(2),
account?.currency?.code,
].join(" ")
}}</span>
</template>

<template v-if="items.length" v-slot:body.append>
Expand All @@ -68,12 +73,15 @@
<td></td>
<td>
{{
items
.reduce(
(acc, item) => acc + (item.amount || 0) * (item.price || 0),
0
)
.toFixed(2)
[
items
.reduce(
(acc, item) => acc + (item.amount || 0) * (item.price || 0),
0
)
.toFixed(2),
account?.currency?.code,
].join(" ")
}}
</td>
<td></td>
Expand Down
30 changes: 19 additions & 11 deletions admin-ui/src/components/plan/event-overrides.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,28 @@
<v-card-title v-else>New event override</v-card-title>

<v-text-field
:rules="[requiredRule, uniqueKeyRule]"
:rules="[requiredRule]"
v-model="newOverride.key"
label="Key"
/>
<v-text-field
:rules="[requiredRule, uniqueOverrideRule]"
:rules="[requiredRule]"
v-model="newOverride.override"
label="Override"
/>

<div class="d-flex justify-center">
<v-card-title style="color: red" v-if="isNotUniqueOverride">{{
"Already overrided!"
}}</v-card-title>
</div>

<div class="d-flex justify-end">
<v-btn @click="isAddOverrideOpen = false">Close</v-btn>
<v-btn
@click="addNewEvent"
:loading="isAddOverrideLoading"
:disabled="isNotUniqueOverride"
class="ml-3"
>{{ isEditOverride ? "Edit" : "Add" }}</v-btn
>
Expand All @@ -81,7 +88,7 @@
</template>

<script setup>
import { onMounted, ref, toRefs, watch } from "vue";
import { computed, onMounted, ref, toRefs, watch } from "vue";
import api from "@/api";
const props = defineProps(["template"]);
Expand All @@ -103,14 +110,15 @@ const editedOverride = ref(false);
onMounted(() => setEventOverrides());
const requiredRule = (val) => !!val || "Field required";
const uniqueKeyRule = (val) =>
isEditOverride.value ||
!eventOverrides.value.find((override) => override.key === val) ||
"Already overrided!";
const uniqueOverrideRule = (val) =>
isEditOverride.value ||
!eventOverrides.value.find((override) => override.override === val) ||
"Already overrided!";
const isNotUniqueOverride = computed(
() =>
!isEditOverride.value &&
eventOverrides.value.find(
(override) =>
override.override === newOverride.value.override &&
override.key === newOverride.value.key
)
);
const setEventOverrides = () => {
eventOverrides.value = [...template.value.customEvents];
Expand Down
4 changes: 4 additions & 0 deletions admin-ui/src/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ export function getSecondsByDays(days) {

export function getState(item) {
if (!item.state) return item?.data?.is_monitored ? "ERROR" : "LCM_INIT";
if (!item.state.state)
return item?.state?.meta?.lcm_state_str
? item?.state.meta.lcm_state_str.toUpperCase()
: "ERROR";

return item.state.state;
}
Expand Down
14 changes: 10 additions & 4 deletions admin-ui/src/views/InvoiceCreate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@
</v-select>
</div>

<div class="item d-flex">
<div class="item d-flex" style="width: 450px">
<accounts-autocomplete
advanced
:loading="isInstancesLoading"
@input="onChangeAccount"
:disabled="isEdit"
Expand Down Expand Up @@ -221,7 +222,7 @@
color="background-light"
@click="downloadInvoice"
>
download
download <v-icon small>mdi-download</v-icon>
</v-btn>

<confirm-dialog
Expand Down Expand Up @@ -323,7 +324,7 @@ import { useStore } from "@/store";
import NocloudExpansionPanels from "@/components/ui/nocloudExpansionPanels.vue";
import datePicker from "@/components/ui/datePicker.vue";
import InvoiceItemsTable from "@/components/invoiceItemsTable.vue";
import { useRouter } from "vue-router/composables";
import { useRoute, useRouter } from "vue-router/composables";
import {
BillingStatus,
CreateInvoiceRequest,
Expand All @@ -345,6 +346,7 @@ const emit = defineEmits(["refresh"]);
const store = useStore();
const router = useRouter();
const route = useRoute();
const { getInvoiceStatusColor, getTotalColor } = useInvoices();
const newInvoice = ref({
Expand Down Expand Up @@ -412,7 +414,7 @@ const changeStatusBtns = [
{
title: "Unpaid",
status: "UNPAID",
disabled: ["TERMINATED", "RETURNED", "DRAFT", "PAID"],
disabled: ["TERMINATED", "RETURNED", "DRAFT"],
},
{
title: "cancel",
Expand All @@ -431,6 +433,10 @@ onMounted(async () => {
setInvoice();
isInstancesLoading.value = false;
if (route.query.account) {
newInvoice.value.account = route.query.account;
}
});
const isBalanceInvoice = computed(() => newInvoice.value.type === "BALANCE");
Expand Down
6 changes: 6 additions & 0 deletions admin-ui/src/views/Invoices.vue
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ const defaultLayouts = computed(() => ({
fields: ["status"],
id: "id-unpaid",
},
paid: {
title: "Paid",
filter: { status: [1] },
fields: ["status"],
id: "id-paid",
},
overdue: {
id: "id-overdue",
title: "Overdue",
Expand Down
Loading

0 comments on commit 23c5f0a

Please sign in to comment.