Update giving reports

test
dan 2019-12-31 00:58:06 -07:00
parent 4b5a889efc
commit 27f9a5f3f3
6 changed files with 160 additions and 31 deletions

View File

@ -2236,6 +2236,37 @@
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true "dev": true
}, },
"chart.js": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.3.tgz",
"integrity": "sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==",
"requires": {
"chartjs-color": "^2.1.0",
"moment": "^2.10.2"
}
},
"chartjs-color": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
"integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
"requires": {
"chartjs-color-string": "^0.6.0",
"color-convert": "^1.9.3"
}
},
"chartjs-color-string": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
"integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
"requires": {
"color-name": "^1.0.0"
}
},
"chartjs-plugin-datalabels": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-0.7.0.tgz",
"integrity": "sha512-PKVUX14nYhH0wcdCpgOoC39Gbzvn6cZ7O9n+bwc02yKD9FTnJ7/TSrBcfebmolFZp1Rcicr9xbT0a5HUbigS7g=="
},
"chokidar": { "chokidar": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
@ -2432,7 +2463,6 @@
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": { "requires": {
"color-name": "1.1.3" "color-name": "1.1.3"
} }
@ -2440,8 +2470,7 @@
"color-name": { "color-name": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
"dev": true
}, },
"colors": { "colors": {
"version": "1.1.2", "version": "1.1.2",
@ -6392,6 +6421,11 @@
"minimist": "0.0.8" "minimist": "0.0.8"
} }
}, },
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",

View File

@ -21,6 +21,8 @@
"@angular/platform-browser": "~7.2.0", "@angular/platform-browser": "~7.2.0",
"@angular/platform-browser-dynamic": "~7.2.0", "@angular/platform-browser-dynamic": "~7.2.0",
"@angular/router": "~7.2.0", "@angular/router": "~7.2.0",
"chart.js": "^2.9.3",
"chartjs-plugin-datalabels": "^0.7.0",
"core-js": "^2.5.4", "core-js": "^2.5.4",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"rxjs": "~6.3.3", "rxjs": "~6.3.3",

View File

@ -16,17 +16,18 @@ export class ContributorAllReportsComponent implements OnInit {
constructor(private printService: PrintService, private userService: UserService, private transactionService: TransactionService) { } constructor(private printService: PrintService, private userService: UserService, private transactionService: TransactionService) { }
ngOnInit() { ngOnInit() {
const query = forkJoin([this.userService.getAll(), this.transactionService.getByYear(2019)]); const query = forkJoin([this.userService.getAll(), this.transactionService.getByYear(2019), this.transactionService.getByYear(2018)]);
query.subscribe(res => this.setup(res[0], res[1])); query.subscribe(res => this.setup(res[0], res[1], res[2]));
this.printService.setPrinting(true); this.printService.setPrinting(true);
} }
private setup(contributorResult, transactionResult) { private setup(contributorResult, transactionResult, priorYearTransactionResult) {
const contributors = contributorResult.users; const contributors = contributorResult.users;
const transactions = transactionResult.transactions; const transactions = transactionResult.transactions;
const priorYearTransactions = priorYearTransactionResult.transactions;
const contrib = {}; const contrib = {};
transactions.forEach(t => { transactions.forEach(t => {
if (contrib.hasOwnProperty(t.contributorId)) { if (contrib.hasOwnProperty(t.contributorId)) {
@ -35,6 +36,7 @@ export class ContributorAllReportsComponent implements OnInit {
const con = contributors.find(c => c.id === t.contributorId); const con = contributors.find(c => c.id === t.contributorId);
if (con) { if (con) {
contrib[con.id] = {contributor: con, transactions: [t]}; contrib[con.id] = {contributor: con, transactions: [t]};
contrib[con.id].priorYearTransactions = priorYearTransactions.filter(t => t.contributorId === con.id);
this.contributors.push(contrib[con.id]); this.contributors.push(contrib[con.id]);
} else { } else {
console.error('coould not find contributor for', t); console.error('coould not find contributor for', t);

View File

@ -29,12 +29,28 @@
display: flex; display: flex;
} }
.flex-direction-column {
flex-direction: column;
}
.flex-align-center { .flex-align-center {
align-items: center; align-items: center;
} }
.flex-justify-space-between {
justify-content: space-between;
}
.flex-align-space-between {
align-content: space-between;
}
.flex-align-top { .flex-align-top {
align-items: baseline; align-items: start;
}
.flex-align-stretch {
align-items: stretch;
} }
.flex-justify-center { .flex-justify-center {

View File

@ -3,13 +3,13 @@
<div class="h-100 flex flex-align-center flex-justify-center flex-direction-column"> <div class="h-100 flex flex-align-center flex-justify-center flex-direction-column">
<img src="../../../assets/images/original/logo_dark.png"> <img src="../../../assets/images/original/logo_dark.png">
<p class="mt-5"> <p class="mt-5">
Old Fashion Baptist Church Contribution Report {{taxYear}} {{index}} Old Fashion Baptist Church Contribution Report {{taxYear}}
</p> </p>
<p class="mt-5"> <p class="mt-5">
{{contributorName}} {{contributorName}}
</p> </p>
<p>{{contributorStreet}}</p> <p *ngIf="contributorStreet && contributorCity && contributorState && contributorZip">{{contributorStreet}}</p>
<p>{{contributorCity}} {{contributorState}}, {{contributorZip}}</p> <p *ngIf="contributorStreet && contributorCity && contributorState && contributorZip">{{contributorCity}} {{contributorState}}, {{contributorZip}}</p>
</div> </div>
<div class="page-break-before"> <div class="page-break-before">
@ -28,14 +28,13 @@
<hr class="hr mt-20"> <hr class="hr mt-20">
<h2 class="text-center mt-20">Old Fashion Baptist Church Giving Statement {{taxYear}}</h2> <h2 class="text-center mt-20">Old Fashion Baptist Church Giving Statement {{taxYear}}</h2>
<hr class="mt-20"> <hr class="mt-20">
<div class="flex flex-align-top flex-justify-space-between"> <div class="flex flex-align-stretch flex-justify-space-between">
<div class="mt-20"> <div class="mt-20 mb-20 flex flex-direction-column flex-justify-space-between">
<p><b>Name: </b>{{contributorName}}</p> <div class="mt-20">
<p><b>Tax Year: </b>{{taxYear}}</p> <p><b>Name: </b>{{contributorName}}</p>
<p><b>Registration Code: </b>{{registrationCode}}</p> <p><b>Tax Year: </b>{{taxYear}}</p>
</div> </div>
<div class="mt-20"> <table class="cell-padding-5 borders mt-20 w-100">
<table class="cell-padding-5 borders">
<thead> <thead>
<tr> <tr>
<th colspan="2">{{taxYear}} Giving Summary</th> <th colspan="2">{{taxYear}} Giving Summary</th>
@ -57,16 +56,18 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="mt-20">
<canvas #chart width="400" height="300"></canvas>
</div>
</div> </div>
<div class="mt-20"> <div>
Thank you for your contribution. The information provided in this statement reflects Thank you for your contribution. The information provided in this statement reflects
your contributions on record for tax year {{taxYear}}. The chart below provides current and your contributions on record for tax year {{taxYear}}.
historical data (if available) for informational purposes only. The data on the following No goods or services were provided in exchange for your contribution.
pages includes a detail listing of contributions for {{taxYear}}.
</div> </div>
</div> </div>
<table class="highlight-even cell-padding-5 w-100 borders page-break-before"> <table class="highlight-even cell-padding-5 w-100 borders mt-20">
<thead> <thead>
<tr> <tr>
<th class="text-left">Date</th> <th class="text-left">Date</th>
@ -79,7 +80,7 @@
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let t of transactions"> <tr *ngFor="let t of transactions">
<td nowrap>{{t.date | date:'shortDate'}}</td> <td nowrap>{{t.date | date:'MM-dd-yyyy'}}</td>
<td nowrap>{{t.type === 0 ? 'Cash' : 'Check'}}</td> <td nowrap>{{t.type === 0 ? 'Cash' : 'Check'}}</td>
<td nowrap>{{t.checkNumber}}</td> <td nowrap>{{t.checkNumber}}</td>
<td nowrap>{{t.fund === 0 ? 'General' : 'Missions'}}</td> <td nowrap>{{t.fund === 0 ? 'General' : 'Missions'}}</td>

View File

@ -1,6 +1,8 @@
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input, ViewChild, ElementRef } from '@angular/core';
import { PrintService } from '../../services/print-service'; import { PrintService } from '../../services/print-service';
import { Transaction } from '../add-transaction-page/transaction'; import { Transaction } from '../add-transaction-page/transaction';
import Chart from 'chart.js';
import ChartDataLabels from 'chartjs-plugin-datalabels';
@Component({ @Component({
selector: 'app-contributor-yearly-report', selector: 'app-contributor-yearly-report',
@ -9,20 +11,34 @@ import { Transaction } from '../add-transaction-page/transaction';
}) })
export class ContributorYearlyReportComponent implements OnInit { export class ContributorYearlyReportComponent implements OnInit {
@ViewChild('chart') chartElement:ElementRef;
@Input() index: number; @Input() index: number;
@Input() contributorTransactions: {contributor: {}, transactions: {}}; @Input() contributorTransactions: {contributor: {}, transactions: {}, priorYearTransactions: {}};
public transactions: Transaction[] = []; public transactions: Transaction[] = [];
public contributorName: string = 'Bob and Jill Handerson'; public priorTransactions: Transaction[] = [];
public get contributorName(): string {
const first = (<any>this.contributorTransactions.contributor).firstName;
const last = (<any>this.contributorTransactions.contributor).lastName;
if (last && first) {
return last + ', ' + first;
} else if (last) {
return last;
} else if (first) {
return first;
} else {
return '';
}
}
public contributorStreet: string = '7878 Washington St'; public contributorStreet: string = '7878 Washington St';
public contributorCity: string = 'Butte'; public contributorCity: string = 'Butte';
public contributorState: string = 'MT'; public contributorState: string = 'MT';
public contributorZip: string = '59701'; public contributorZip: string = '59701';
public taxYear: number = 2019; public taxYear: number = 2019;
public registrationCode: string = 'HDIJDHDFD*#*@';
public rowsFirstPage: number = 13;
public rowsPerPage: number = 32; public rowsPerPage: number = 32;
public get pages(): number { public get pages(): number {
return Math.ceil(this.transactions.length / this.rowsPerPage) + 2; return Math.ceil((this.transactions.length - this.rowsFirstPage) / this.rowsPerPage) + 2;
} }
public get pagesOdd(): boolean { public get pagesOdd(): boolean {
return !(this.pages % 2 == 0) return !(this.pages % 2 == 0)
@ -32,12 +48,12 @@ export class ContributorYearlyReportComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.contributorCity = (<any>this.contributorTransactions.contributor).city; this.contributorCity = (<any>this.contributorTransactions.contributor).city;
this.contributorName = (<any>this.contributorTransactions.contributor).display;
this.contributorState = (<any>this.contributorTransactions.contributor).state; this.contributorState = (<any>this.contributorTransactions.contributor).state;
this.contributorStreet = (<any>this.contributorTransactions.contributor).street; this.contributorStreet = (<any>this.contributorTransactions.contributor).street;
this.contributorZip = (<any>this.contributorTransactions.contributor).zip; this.contributorZip = (<any>this.contributorTransactions.contributor).zip;
this.transactions = <any>this.contributorTransactions.transactions; this.transactions = <any>this.contributorTransactions.transactions;
this.priorTransactions = <any>this.contributorTransactions.priorYearTransactions;
this.renderChart();
} }
public totalGeneral() { public totalGeneral() {
@ -46,10 +62,68 @@ export class ContributorYearlyReportComponent implements OnInit {
return sum; return sum;
} }
public priorGeneral() {
let sum = 0;
this.priorTransactions.filter(t => t.fundId === 1).forEach(t => sum += t.amount);
return sum;
}
public totalMissions() { public totalMissions() {
let sum = 0; let sum = 0;
this.transactions.filter(t => t.fundId === 2).forEach(t => sum += t.amount); this.transactions.filter(t => t.fundId === 2).forEach(t => sum += t.amount);
return sum; return sum;
} }
public priorMissions() {
let sum = 0;
this.priorTransactions.filter(t => t.fundId === 2).forEach(t => sum += t.amount);
return sum;
}
private renderChart() {
var myChart = new Chart(this.chartElement.nativeElement, {
plugins: [ChartDataLabels],
type: 'bar',
data: {
labels: ['2018', '2019'],
datasets: [{
label: 'General',
data: [this.priorGeneral(), this.totalGeneral()],
backgroundColor: 'rgba(54, 245, 162, 0.2)',
borderColor: 'rgba(54, 245, 162, 1)',
borderWidth: 1
}, {
label: 'Missions',
data: [this.priorMissions(), this.totalMissions()],
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options:{
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
},
plugins:{
datalabels:{
font:{
weight: 'bold'
},
formatter: function(value, context){
if (value === 0) {
return '';
}
return '$' + value.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
}
}
}
}
});
}
} }