Tag: v7.0.2
Fix: Attendance Type and Account Type objects were borking as their convenience methods were not returning anything Fix: Employee Benefits and Incentive post voucher did not reload the page Fix: For all vouchers, to prevent double data loading on save / update either reload data or navigate, don't reload data and then navigate so that the data appears once and then disappears
This commit is contained in:
parent
b7a1c5b816
commit
6ccb3634be
brewman/models
overlord
setup.py@ -435,7 +435,7 @@ class AttendanceType:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def list(cls):
|
def list(cls):
|
||||||
list = [
|
return [
|
||||||
AttendanceType(0, "Not Set", 0),
|
AttendanceType(0, "Not Set", 0),
|
||||||
AttendanceType(1, "Present", 1),
|
AttendanceType(1, "Present", 1),
|
||||||
AttendanceType(2, "Off Day", 1),
|
AttendanceType(2, "Off Day", 1),
|
||||||
@ -449,15 +449,14 @@ class AttendanceType:
|
|||||||
AttendanceType(10, "Half Day + PL", 1),
|
AttendanceType(10, "Half Day + PL", 1),
|
||||||
AttendanceType(11, "Half Day + CL", 1),
|
AttendanceType(11, "Half Day + CL", 1),
|
||||||
]
|
]
|
||||||
return list
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def by_name(cls, name):
|
def by_name(cls, name):
|
||||||
next(i for i in cls.list() if i.name == name)
|
return next(i for i in cls.list() if i.name == name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def by_id(cls, id_):
|
def by_id(cls, id_):
|
||||||
next(i for i in cls.list() if i.id == id_)
|
return next(i for i in cls.list() if i.id == id_)
|
||||||
|
|
||||||
|
|
||||||
class AccountType:
|
class AccountType:
|
||||||
@ -499,11 +498,11 @@ class AccountType:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def by_name(cls, name):
|
def by_name(cls, name):
|
||||||
next(i for i in cls.list() if i.name == name)
|
return next(i for i in cls.list() if i.name == name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def by_id(cls, id_):
|
def by_id(cls, id_):
|
||||||
next(i for i in cls.list() if i.id == id_)
|
return next(i for i in cls.list() if i.id == id_)
|
||||||
|
|
||||||
|
|
||||||
class DbSetting(Base):
|
class DbSetting(Base):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "overlord",
|
"name": "overlord",
|
||||||
"version": "7.0.1",
|
"version": "7.0.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
|
@ -52,17 +52,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.route.data
|
this.route.data
|
||||||
.subscribe((data: { voucher: Voucher }) => {
|
.subscribe((data: { voucher: Voucher }) => {
|
||||||
this.voucher = data.voucher;
|
this.loadVoucher(data.voucher);
|
||||||
this.form.setValue({
|
|
||||||
date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(),
|
|
||||||
addRow: {
|
|
||||||
employee: '1',
|
|
||||||
grossSalary: '',
|
|
||||||
daysWorked: ''
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.dataSource = new EmployeeBenefitsDataSource(this.benefitsObservable);
|
|
||||||
this.benefitsObservable.next(this.voucher.employeeBenefits);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +62,20 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadVoucher(voucher) {
|
||||||
|
this.voucher = voucher;
|
||||||
|
this.form.setValue({
|
||||||
|
date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(),
|
||||||
|
addRow: {
|
||||||
|
employee: '1',
|
||||||
|
grossSalary: '',
|
||||||
|
daysWorked: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.dataSource = new EmployeeBenefitsDataSource(this.benefitsObservable);
|
||||||
|
this.benefitsObservable.next(this.voucher.employeeBenefits);
|
||||||
|
}
|
||||||
|
|
||||||
createForm() {
|
createForm() {
|
||||||
this.form = this.fb.group({
|
this.form = this.fb.group({
|
||||||
date: '',
|
date: '',
|
||||||
@ -181,6 +185,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
|||||||
this.ser.post(this.voucher.id)
|
this.ser.post(this.voucher.id)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
|
this.loadVoucher(result);
|
||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
@ -190,11 +195,16 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getVoucher())
|
const voucher: Voucher = this.getVoucher();
|
||||||
|
this.ser.saveOrUpdate(voucher)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
|
if (voucher.id === result.id) {
|
||||||
|
this.loadVoucher(result);
|
||||||
|
} else {
|
||||||
this.router.navigate(['/employee-benefits', result.id]);
|
this.router.navigate(['/employee-benefits', result.id]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error);
|
this.toaster.show('Danger', error);
|
||||||
|
@ -46,20 +46,24 @@ export class IncentiveComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.route.data
|
this.route.data
|
||||||
.subscribe((data: { voucher: Voucher }) => {
|
.subscribe((data: { voucher: Voucher }) => {
|
||||||
this.voucher = data.voucher;
|
this.loadVoucher(data.voucher);
|
||||||
this.form.get('date').setValue(moment(this.voucher.date, 'DD-MMM-YYYY').toDate());
|
|
||||||
this.form.setControl('incentives', this.fb.array(
|
|
||||||
this.voucher.incentives.map(
|
|
||||||
x => this.fb.group({
|
|
||||||
points: x.points
|
|
||||||
})
|
|
||||||
)
|
|
||||||
));
|
|
||||||
this.dataSource = new IncentiveDataSource(this.incentiveObservable);
|
|
||||||
this.incentiveObservable.next(this.voucher.incentives);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadVoucher(voucher) {
|
||||||
|
this.voucher = voucher;
|
||||||
|
this.form.get('date').setValue(moment(this.voucher.date, 'DD-MMM-YYYY').toDate());
|
||||||
|
this.form.setControl('incentives', this.fb.array(
|
||||||
|
this.voucher.incentives.map(
|
||||||
|
x => this.fb.group({
|
||||||
|
points: x.points
|
||||||
|
})
|
||||||
|
)
|
||||||
|
));
|
||||||
|
this.dataSource = new IncentiveDataSource(this.incentiveObservable);
|
||||||
|
this.incentiveObservable.next(this.voucher.incentives);
|
||||||
|
}
|
||||||
|
|
||||||
createForm() {
|
createForm() {
|
||||||
this.form = this.fb.group({
|
this.form = this.fb.group({
|
||||||
date: '',
|
date: '',
|
||||||
@ -74,17 +78,7 @@ export class IncentiveComponent implements OnInit {
|
|||||||
if (x !== this.voucher.date && !this.voucher.id) {
|
if (x !== this.voucher.date && !this.voucher.id) {
|
||||||
return this.ser.getIncentive(x)
|
return this.ser.getIncentive(x)
|
||||||
.subscribe((voucher: Voucher) => {
|
.subscribe((voucher: Voucher) => {
|
||||||
this.voucher = voucher;
|
this.loadVoucher(voucher);
|
||||||
this.form.get('date').setValue(moment(this.voucher.date, 'DD-MMM-YYYY').toDate());
|
|
||||||
this.form.setControl('incentives', this.fb.array(
|
|
||||||
this.voucher.incentives.map(
|
|
||||||
i => this.fb.group({
|
|
||||||
points: i.points
|
|
||||||
})
|
|
||||||
)
|
|
||||||
));
|
|
||||||
this.dataSource = new IncentiveDataSource(this.incentiveObservable);
|
|
||||||
this.incentiveObservable.next(this.voucher.incentives);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -137,6 +131,7 @@ export class IncentiveComponent implements OnInit {
|
|||||||
this.ser.post(this.voucher.id)
|
this.ser.post(this.voucher.id)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
|
this.loadVoucher(result);
|
||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
@ -146,11 +141,15 @@ export class IncentiveComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getVoucher())
|
const voucher: Voucher = this.getVoucher();
|
||||||
|
this.ser.saveOrUpdate(voucher)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
this.toaster.show('Success', '');
|
if (voucher.id === result.id) {
|
||||||
|
this.loadVoucher(result);
|
||||||
|
} else {
|
||||||
this.router.navigate(['/incentive', result.id]);
|
this.router.navigate(['/incentive', result.id]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error);
|
this.toaster.show('Danger', error);
|
||||||
|
@ -215,12 +215,16 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getVoucher())
|
const voucher: Voucher = this.getVoucher();
|
||||||
|
this.ser.saveOrUpdate(voucher)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
this.loadVoucher(result);
|
|
||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
|
if (voucher.id === result.id) {
|
||||||
|
this.loadVoucher(result);
|
||||||
|
} else {
|
||||||
this.router.navigate(['/issue', result.id]);
|
this.router.navigate(['/issue', result.id]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error);
|
this.toaster.show('Danger', error);
|
||||||
|
@ -17,7 +17,7 @@ import {ToasterService} from '../core/toaster.service';
|
|||||||
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
|
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
|
||||||
import {JournalDialogComponent} from './journal-dialog.component';
|
import {JournalDialogComponent} from './journal-dialog.component';
|
||||||
import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
|
import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
|
||||||
import {Hotkey, HotkeysService} from "angular2-hotkeys";
|
import {Hotkey, HotkeysService} from 'angular2-hotkeys';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-journal',
|
selector: 'app-journal',
|
||||||
@ -66,13 +66,15 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
return false; // Prevent bubbling
|
return false; // Prevent bubbling
|
||||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||||
this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
|
this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
|
||||||
if (this.canSave())
|
if (this.canSave()) {
|
||||||
this.save();
|
this.save();
|
||||||
|
}
|
||||||
return false; // Prevent bubbling
|
return false; // Prevent bubbling
|
||||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||||
this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
|
this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
|
||||||
if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('post-vouchers') !== -1)
|
if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('post-vouchers') !== -1) {
|
||||||
this.post();
|
this.post();
|
||||||
|
}
|
||||||
return false; // Prevent bubbling
|
return false; // Prevent bubbling
|
||||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||||
}
|
}
|
||||||
@ -225,12 +227,16 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getVoucher())
|
const voucher: Voucher = this.getVoucher();
|
||||||
|
this.ser.saveOrUpdate(voucher)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
this.loadVoucher(result);
|
|
||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
|
if (voucher.id === result.id) {
|
||||||
|
this.loadVoucher(result);
|
||||||
|
} else {
|
||||||
this.router.navigate(['/journal', result.id]);
|
this.router.navigate(['/journal', result.id]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error);
|
this.toaster.show('Danger', error);
|
||||||
|
@ -17,7 +17,7 @@ import {ToasterService} from '../core/toaster.service';
|
|||||||
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
|
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
|
||||||
import {PaymentDialogComponent} from './payment-dialog.component';
|
import {PaymentDialogComponent} from './payment-dialog.component';
|
||||||
import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
|
import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
|
||||||
import {Hotkey, HotkeysService} from "angular2-hotkeys";
|
import {Hotkey, HotkeysService} from 'angular2-hotkeys';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-payment',
|
selector: 'app-payment',
|
||||||
@ -229,12 +229,16 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getVoucher())
|
const voucher: Voucher = this.getVoucher();
|
||||||
|
this.ser.saveOrUpdate(voucher)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
this.loadVoucher(result);
|
|
||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
|
if (voucher.id === result.id) {
|
||||||
|
this.loadVoucher(result);
|
||||||
|
} else {
|
||||||
this.router.navigate(['/payment', result.id]);
|
this.router.navigate(['/payment', result.id]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error);
|
this.toaster.show('Danger', error);
|
||||||
|
@ -215,12 +215,16 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getVoucher())
|
const voucher: Voucher = this.getVoucher();
|
||||||
|
this.ser.saveOrUpdate(voucher)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
this.loadVoucher(result);
|
|
||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
|
if (voucher.id === result.id) {
|
||||||
|
this.loadVoucher(result);
|
||||||
|
} else {
|
||||||
this.router.navigate(['/purchase-return', result.id]);
|
this.router.navigate(['/purchase-return', result.id]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error);
|
this.toaster.show('Danger', error);
|
||||||
|
@ -228,12 +228,16 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getVoucher())
|
const voucher: Voucher = this.getVoucher();
|
||||||
|
this.ser.saveOrUpdate(voucher)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
this.loadVoucher(result);
|
|
||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
|
if (voucher.id === result.id) {
|
||||||
|
this.loadVoucher(result);
|
||||||
|
} else {
|
||||||
this.router.navigate(['/purchase', result.id]);
|
this.router.navigate(['/purchase', result.id]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error);
|
this.toaster.show('Danger', error);
|
||||||
|
@ -17,7 +17,7 @@ import {ToasterService} from '../core/toaster.service';
|
|||||||
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
|
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
|
||||||
import {ReceiptDialogComponent} from './receipt-dialog.component';
|
import {ReceiptDialogComponent} from './receipt-dialog.component';
|
||||||
import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
|
import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
|
||||||
import {Hotkey, HotkeysService} from "angular2-hotkeys";
|
import {Hotkey, HotkeysService} from 'angular2-hotkeys';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-receipt',
|
selector: 'app-receipt',
|
||||||
@ -70,13 +70,15 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
return false; // Prevent bubbling
|
return false; // Prevent bubbling
|
||||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||||
this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
|
this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
|
||||||
if (this.canSave())
|
if (this.canSave()) {
|
||||||
this.save();
|
this.save();
|
||||||
|
}
|
||||||
return false; // Prevent bubbling
|
return false; // Prevent bubbling
|
||||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||||
this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
|
this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
|
||||||
if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('post-vouchers') !== -1)
|
if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('post-vouchers') !== -1) {
|
||||||
this.post();
|
this.post();
|
||||||
|
}
|
||||||
return false; // Prevent bubbling
|
return false; // Prevent bubbling
|
||||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||||
}
|
}
|
||||||
@ -228,12 +230,16 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
this.ser.saveOrUpdate(this.getVoucher())
|
const voucher: Voucher = this.getVoucher();
|
||||||
|
this.ser.saveOrUpdate(voucher)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(result) => {
|
(result) => {
|
||||||
this.loadVoucher(result);
|
|
||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
|
if (voucher.id === result.id) {
|
||||||
|
this.loadVoucher(result);
|
||||||
|
} else {
|
||||||
this.router.navigate(['/receipt', result.id]);
|
this.router.navigate(['/receipt', result.id]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error);
|
this.toaster.show('Danger', error);
|
||||||
|
2
setup.py
2
setup.py
@ -11,7 +11,7 @@ with open(os.path.join(here, 'requirements.txt'), "r") as r:
|
|||||||
requires = r.read().splitlines()
|
requires = r.read().splitlines()
|
||||||
|
|
||||||
setup(name='brewman',
|
setup(name='brewman',
|
||||||
version='7.0.1',
|
version='7.0.2',
|
||||||
description='brewman',
|
description='brewman',
|
||||||
long_description=README + '\n\n' + CHANGES,
|
long_description=README + '\n\n' + CHANGES,
|
||||||
classifiers=[
|
classifiers=[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user