diff --git a/luthor/alembic/versions/74058d75b7a0_initial_commit.py b/luthor/alembic/versions/74058d75b7a0_initial_commit.py index d3f13d1..671be10 100644 --- a/luthor/alembic/versions/74058d75b7a0_initial_commit.py +++ b/luthor/alembic/versions/74058d75b7a0_initial_commit.py @@ -256,6 +256,7 @@ def upgrade(): sa.Column("bench", sa.Unicode(length=255), nullable=True), sa.Column("proceedings", sa.Unicode(length=2000), nullable=True), sa.Column("compliance_date", sa.Date(), nullable=True), + sa.Column("compliance_done", sa.Boolean(), nullable=False, server_default=expression.true()), sa.Column("next_hearing_date", sa.Date(), nullable=False), sa.Column("court_status_id", postgresql.UUID(as_uuid=True), nullable=True), sa.Column("old_court_status_id", sa.Integer(), nullable=True), diff --git a/luthor/luthor/models/hearing.py b/luthor/luthor/models/hearing.py index 3543e8f..96a06c2 100644 --- a/luthor/luthor/models/hearing.py +++ b/luthor/luthor/models/hearing.py @@ -1,8 +1,17 @@ import uuid -from sqlalchemy import Column, Date, ForeignKey, Unicode, UniqueConstraint, text +from sqlalchemy import ( + Boolean, + Column, + Date, + ForeignKey, + Unicode, + UniqueConstraint, + text, +) from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship +from sqlalchemy.sql import expression from .meta import Base @@ -28,6 +37,9 @@ class Hearing(Base): next_hearing_date = Column("next_hearing_date", Date, nullable=False, index=True) compliance_date = Column("compliance_date", Date, nullable=False, index=True) court_status_id = Column("court_status_id", UUID(as_uuid=True), ForeignKey("court_statuses.id"), nullable=False) + compliance_done = Column( + "compliance_done", Boolean, nullable=False, server_default=expression.true(), default=False + ) court_status = relationship("CourtStatus", back_populates="hearings") case = relationship("Case", back_populates="hearings") @@ -41,6 +53,7 @@ class Hearing(Base): proceedings=None, compliance_date=None, next_hearing_date=None, + compliance_done=None, court_status_id=None, id_=None, ): @@ -51,5 +64,6 @@ class Hearing(Base): self.bench = bench self.proceedings = proceedings self.compliance_date = compliance_date + self.compliance_done = compliance_done self.next_hearing_date = next_hearing_date self.court_status_id = court_status_id diff --git a/luthor/luthor/routers/case.py b/luthor/luthor/routers/case.py index a2e21b3..0c18908 100644 --- a/luthor/luthor/routers/case.py +++ b/luthor/luthor/routers/case.py @@ -75,8 +75,9 @@ def save( bench=h.bench, proceedings=h.proceedings, compliance_date=h.compliance_date, + compliance_done=h.compliance_done, next_hearing_date=h.next_hearing_date, - court_status_id=h.court_status.id_ if h.court_status is not None else None, + court_status_id=h.court_status.id_, ) for h in data.hearings ], @@ -152,6 +153,7 @@ def update( h.bench = d.bench h.proceedings = d.proceedings h.compliance_date = d.compliance_date + h.compliance_done = d.compliance_done h.next_hearing_date = d.next_hearing_date h.court_status_id = d.court_status.id_ if d.court_status is not None else None for d in [d for d in data.hearings if d.id_ is None]: @@ -161,8 +163,9 @@ def update( bench=d.bench, proceedings=d.proceedings, compliance_date=d.compliance_date, + compliance_done=d.compliance_done, next_hearing_date=d.next_hearing_date, - court_status_id=d.court_status.id_ if d.court_status is not None else None, + court_status_id=d.court_status.id_, ) item.hearings.append(h) db.add(h) @@ -298,6 +301,7 @@ def case_info(item: Case) -> schemas.Case: bench=h.bench if h.bench is not None else "", proceedings=h.proceedings if h.proceedings is not None else "", complianceDate=h.compliance_date, + complianceDone=h.compliance_date is not None and h.compliance_done, nextHearingDate=h.next_hearing_date, courtStatus=schemas.CourtStatusLink(id=h.court_status.id, name=h.court_status.name), ) diff --git a/luthor/luthor/routers/cause_list.py b/luthor/luthor/routers/cause_list.py index eea8eac..de769a6 100644 --- a/luthor/luthor/routers/cause_list.py +++ b/luthor/luthor/routers/cause_list.py @@ -99,6 +99,7 @@ def case_info(item: Case) -> schemas.Case: bench=h.bench if h.bench is not None else "", proceedings=h.proceedings if h.proceedings is not None else "", complianceDate=h.compliance_date, + complianceDone=h.compliance_date is None and h.compliance_done, nextHearingDate=h.next_hearing_date, courtStatus=schemas.CourtStatusLink(id=h.court_status.id, name=h.court_status.name) if h.court_status is not None diff --git a/luthor/luthor/routers/compliance_list.py b/luthor/luthor/routers/compliance_list.py index 29fb33d..407f8d6 100644 --- a/luthor/luthor/routers/compliance_list.py +++ b/luthor/luthor/routers/compliance_list.py @@ -1,4 +1,3 @@ -from datetime import date, datetime from typing import List import luthor.schemas.compliance_list as schemas @@ -25,34 +24,29 @@ def get_db(): db.close() -@router.get("", response_model=schemas.ComplianceList) +@router.get("", response_model=List[schemas.ComplianceList]) def report_blank( - d: str = None, db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["cases"]), -) -> schemas.ComplianceList: - d = date.today() if d is None else datetime.strptime(d, "%d-%b-%Y").date() - return schemas.ComplianceList( - date=d, - items=get_items(d, db), - ) +) -> List[schemas.ComplianceList]: + return get_items(db) -def get_items(d: date, db: Session) -> List[schemas.ComplianceListItem]: +def get_items(db: Session) -> List[schemas.ComplianceList]: items = [ - case_info(item, d) + case_info(item) for item in db.query(Case) .join(Case.hearings) - .filter(Hearing.compliance_date >= d) + .filter(Hearing.compliance_date != None, Hearing.compliance_done == False) # noqa: E712, E711 .order_by(Hearing.compliance_date) .all() ] return [item for sublist in items for item in sublist] -def case_info(item: Case, date_: date) -> List[schemas.ComplianceListItem]: +def case_info(item: Case) -> List[schemas.ComplianceList]: return [ - schemas.ComplianceListItem( + schemas.ComplianceList( id=item.id, officeFileNumber=f"{item.case_source.prefix}-{item.office_file_number}", courtNumber=h.court_number if h.court_number is not None else "", @@ -62,5 +56,5 @@ def case_info(item: Case, date_: date) -> List[schemas.ComplianceListItem]: complianceDate=h.compliance_date, ) for h in item.hearings - if h.compliance_date is not None and h.compliance_date >= date_ + if h.compliance_date is not None and h.compliance_done is False ] diff --git a/luthor/luthor/schemas/compliance_list.py b/luthor/luthor/schemas/compliance_list.py index e09fb16..9bdd801 100644 --- a/luthor/luthor/schemas/compliance_list.py +++ b/luthor/luthor/schemas/compliance_list.py @@ -1,14 +1,13 @@ import uuid from datetime import date, datetime -from typing import List from pydantic import BaseModel, validator from . import to_camel -class ComplianceListItem(BaseModel): +class ComplianceList(BaseModel): id_: uuid.UUID office_file_number: str court_number: str @@ -27,19 +26,3 @@ class ComplianceListItem(BaseModel): if isinstance(value, date): return value return datetime.strptime(value, "%d-%b-%Y").date() - - -class ComplianceList(BaseModel): - date_: date - items: List[ComplianceListItem] - - class Config: - anystr_strip_whitespace = True - alias_generator = to_camel - json_encoders = {date: lambda v: v.strftime("%d-%b-%Y")} - - @validator("date_", pre=True) - def parse_date(cls, value): - if isinstance(value, date): - return value - return datetime.strptime(value, "%d-%b-%Y").date() diff --git a/luthor/luthor/schemas/hearing.py b/luthor/luthor/schemas/hearing.py index 71ed304..6289577 100644 --- a/luthor/luthor/schemas/hearing.py +++ b/luthor/luthor/schemas/hearing.py @@ -15,6 +15,7 @@ class HearingIn(BaseModel): bench: str proceedings: str compliance_date: Optional[date] + compliance_done: bool next_hearing_date: date court_status: Optional[CourtStatusLink] diff --git a/otis/src/app/cases/case-detail/case-detail.component.css b/otis/src/app/cases/case-detail/case-detail.component.css index 7d4d15f..e365d05 100644 --- a/otis/src/app/cases/case-detail/case-detail.component.css +++ b/otis/src/app/cases/case-detail/case-detail.component.css @@ -4,3 +4,12 @@ .right-align { text-align: right; } +.checkbox-align { + align-self: center; +} +.not-complied { + background-color: #f8cbad; +} +.complied { + background-color: #c6e0b4; +} diff --git a/otis/src/app/cases/case-detail/case-detail.component.html b/otis/src/app/cases/case-detail/case-detail.component.html index 3acbab0..0dbad7a 100644 --- a/otis/src/app/cases/case-detail/case-detail.component.html +++ b/otis/src/app/cases/case-detail/case-detail.component.html @@ -417,6 +417,20 @@ autocomplete="off" /> + + Next Hearing Date + + + +
- - Next Hearing Date - - - - + Compliance Done?
@@ -555,7 +558,11 @@ - + diff --git a/otis/src/app/cases/case-detail/case-detail.component.ts b/otis/src/app/cases/case-detail/case-detail.component.ts index 5acdf44..884a658 100644 --- a/otis/src/app/cases/case-detail/case-detail.component.ts +++ b/otis/src/app/cases/case-detail/case-detail.component.ts @@ -102,6 +102,7 @@ export class CaseDetailComponent implements OnInit, AfterViewInit { latestStatus: '', proceedings: '', complianceDate: '', + complianceDone: '', nextHearingDate: '', }), }); @@ -360,6 +361,7 @@ export class CaseDetailComponent implements OnInit, AfterViewInit { const complianceDate = formValue.complianceDate ? moment(formValue.complianceDate).format('DD-MMM-YYYY') : null; + const complianceDone = formValue.complianceDone; const nextHearingDate = formValue.nextHearingDate ? moment(formValue.nextHearingDate).format('DD-MMM-YYYY') : null; @@ -372,6 +374,7 @@ export class CaseDetailComponent implements OnInit, AfterViewInit { courtStatus: latestStatus, proceedings, complianceDate, + complianceDone, nextHearingDate, }), ); @@ -387,6 +390,7 @@ export class CaseDetailComponent implements OnInit, AfterViewInit { courtStatus: '', proceedings: '', complianceDate: '', + complianceDone: '', nextHearingDate: '', }); } diff --git a/otis/src/app/cases/case-detail/hearing-dialog.component.html b/otis/src/app/cases/case-detail/hearing-dialog.component.html index bb01e16..3857427 100644 --- a/otis/src/app/cases/case-detail/hearing-dialog.component.html +++ b/otis/src/app/cases/case-detail/hearing-dialog.component.html @@ -28,6 +28,20 @@ autocomplete="off" /> + + Next Hearing Date + + + +
- + Compliance Date - - Next Hearing Date - - - - + Compliance Done?
diff --git a/otis/src/app/cases/case-detail/hearing-dialog.component.ts b/otis/src/app/cases/case-detail/hearing-dialog.component.ts index 83ca196..0ff9d22 100644 --- a/otis/src/app/cases/case-detail/hearing-dialog.component.ts +++ b/otis/src/app/cases/case-detail/hearing-dialog.component.ts @@ -26,6 +26,7 @@ export class HearingDialogComponent implements OnInit { latestStatus: '', proceedings: '', complianceDate: '', + complianceDone: '', nextHearingDate: '', }); } @@ -40,6 +41,7 @@ export class HearingDialogComponent implements OnInit { complianceDate: this.data.hearing.complianceDate ? moment(this.data.hearing.complianceDate, 'DD-MMM-YYYY').toDate() : '', + complianceDone: this.data.hearing.complianceDone, nextHearingDate: this.data.hearing.nextHearingDate ? moment(this.data.hearing.nextHearingDate, 'DD-MMM-YYYY').toDate() : '', @@ -61,6 +63,7 @@ export class HearingDialogComponent implements OnInit { this.data.hearing.complianceDate = formValue.complianceDate ? moment(formValue.complianceDate).format('DD-MMM-YYYY') : null; + this.data.hearing.complianceDone = formValue.complianceDone; this.data.hearing.nextHearingDate = formValue.nextHearingDate ? moment(formValue.nextHearingDate).format('DD-MMM-YYYY') : null; diff --git a/otis/src/app/cases/cases.module.ts b/otis/src/app/cases/cases.module.ts index 89697f2..83bba7c 100644 --- a/otis/src/app/cases/cases.module.ts +++ b/otis/src/app/cases/cases.module.ts @@ -6,6 +6,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { MomentDateAdapter } from '@angular/material-moment-adapter'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; +import { MatCheckboxModule } from '@angular/material/checkbox'; import { DateAdapter, MAT_DATE_FORMATS, @@ -55,6 +56,7 @@ export const MY_FORMATS = { MatPaginatorModule, MatDatepickerModule, MatDialogModule, + MatCheckboxModule, ], declarations: [CaseListComponent, CaseDetailComponent, HearingDialogComponent], providers: [ diff --git a/otis/src/app/compliance-list/compliance-list-datasource.ts b/otis/src/app/compliance-list/compliance-list-datasource.ts index da269fd..e3fadae 100644 --- a/otis/src/app/compliance-list/compliance-list-datasource.ts +++ b/otis/src/app/compliance-list/compliance-list-datasource.ts @@ -4,15 +4,15 @@ import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { merge, Observable, of as observableOf } from 'rxjs'; import { map, tap } from 'rxjs/operators'; -import { ComplianceListItem } from './compliance-list-item'; +import { ComplianceList } from './compliance-list'; -export class ComplianceListDatasource extends DataSource { - constructor(public data: ComplianceListItem[], private paginator?: MatPaginator) { +export class ComplianceListDatasource extends DataSource { + constructor(public data: ComplianceList[], private paginator?: MatPaginator) { super(); } - connect(): Observable { - const dataMutations: (Observable | EventEmitter)[] = [ + connect(): Observable { + const dataMutations: (Observable | EventEmitter)[] = [ observableOf(this.data), ]; if (this.paginator) { @@ -21,18 +21,18 @@ export class ComplianceListDatasource extends DataSource { return merge(...dataMutations) .pipe( - tap((x: ComplianceListItem[]) => { + tap((x: ComplianceList[]) => { if (this.paginator) { this.paginator.length = x.length; } }), ) - .pipe(map((x: ComplianceListItem[]) => this.getPagedData(this.data))); + .pipe(map((x: ComplianceList[]) => this.getPagedData(this.data))); } disconnect() {} - private getPagedData(data: ComplianceListItem[]) { + private getPagedData(data: ComplianceList[]) { if (this.paginator === undefined) { return data; } diff --git a/otis/src/app/compliance-list/compliance-list-item.ts b/otis/src/app/compliance-list/compliance-list-item.ts deleted file mode 100644 index 78e07c0..0000000 --- a/otis/src/app/compliance-list/compliance-list-item.ts +++ /dev/null @@ -1,20 +0,0 @@ -export class ComplianceListItem { - id: string; - officeFileNumber: string; - courtNumber: string; - itemNumber: string; - title: string; - proceedings: string; - complianceDate: string; - - public constructor(init?: Partial) { - this.id = ''; - this.officeFileNumber = ''; - this.courtNumber = ''; - this.itemNumber = ''; - this.title = ''; - this.proceedings = ''; - this.complianceDate = ''; - Object.assign(this, init); - } -} diff --git a/otis/src/app/compliance-list/compliance-list-resolver.service.ts b/otis/src/app/compliance-list/compliance-list-resolver.service.ts index 73412ae..0c2e384 100644 --- a/otis/src/app/compliance-list/compliance-list-resolver.service.ts +++ b/otis/src/app/compliance-list/compliance-list-resolver.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; +import { Resolve } from '@angular/router'; import { Observable } from 'rxjs/internal/Observable'; import { ComplianceList } from './compliance-list'; @@ -11,8 +11,7 @@ import { ComplianceListService } from './compliance-list.service'; export class ComplianceListResolver implements Resolve { constructor(private ser: ComplianceListService) {} - resolve(route: ActivatedRouteSnapshot): Observable { - const date = route.queryParamMap.get('date') || null; - return this.ser.list(date); + resolve(): Observable { + return this.ser.list(); } } diff --git a/otis/src/app/compliance-list/compliance-list.component.html b/otis/src/app/compliance-list/compliance-list.component.html index 1abce9a..ba7c503 100644 --- a/otis/src/app/compliance-list/compliance-list.component.html +++ b/otis/src/app/compliance-list/compliance-list.component.html @@ -3,29 +3,6 @@ Compliances -
-
- - - - - - -
-
diff --git a/otis/src/app/compliance-list/compliance-list.component.ts b/otis/src/app/compliance-list/compliance-list.component.ts index bf466a1..b13ae93 100644 --- a/otis/src/app/compliance-list/compliance-list.component.ts +++ b/otis/src/app/compliance-list/compliance-list.component.ts @@ -14,45 +14,19 @@ import { ComplianceListDatasource } from './compliance-list-datasource'; }) export class ComplianceListComponent implements OnInit { @ViewChild(MatPaginator, { static: true }) paginator?: MatPaginator; - form: FormGroup; - info: ComplianceList = new ComplianceList(); - dataSource: ComplianceListDatasource = new ComplianceListDatasource(this.info.items); + info: ComplianceList[] = []; + dataSource: ComplianceListDatasource = new ComplianceListDatasource(this.info); /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ displayedColumns = ['officeFileNumber', 'title', 'proceedings', 'complianceDate']; - constructor(private route: ActivatedRoute, private router: Router, private fb: FormBuilder) { - // Create form - this.form = this.fb.group({ - date: '', - }); - } + constructor(private route: ActivatedRoute) {} ngOnInit() { this.route.data.subscribe((value) => { - const data = value as { info: ComplianceList }; + const data = value as { info: ComplianceList[] }; this.info = data.info; - this.form.setValue({ - date: moment(this.info.date, 'DD-MMM-YYYY').toDate(), - }); - this.dataSource = new ComplianceListDatasource(this.info.items, this.paginator); - }); - } - - show() { - const info = this.getInfo(); - this.router.navigate(['compliance-list'], { - queryParams: { - date: info.date, - }, - }); - } - - getInfo(): ComplianceList { - const formModel = this.form.value; - - return new ComplianceList({ - date: moment(formModel.date).format('DD-MMM-YYYY'), + this.dataSource = new ComplianceListDatasource(this.info, this.paginator); }); } } diff --git a/otis/src/app/compliance-list/compliance-list.module.ts b/otis/src/app/compliance-list/compliance-list.module.ts index 96ca0bb..cd5a9ff 100644 --- a/otis/src/app/compliance-list/compliance-list.module.ts +++ b/otis/src/app/compliance-list/compliance-list.module.ts @@ -2,23 +2,12 @@ import { CdkTableModule } from '@angular/cdk/table'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FlexLayoutModule } from '@angular/flex-layout'; -import { ReactiveFormsModule } from '@angular/forms'; -import { MomentDateAdapter } from '@angular/material-moment-adapter'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; -import { - DateAdapter, - MAT_DATE_FORMATS, - MAT_DATE_LOCALE, - MatNativeDateModule, -} from '@angular/material/core'; -import { MatDatepickerModule } from '@angular/material/datepicker'; -import { MatDialogModule } from '@angular/material/dialog'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatSelectModule } from '@angular/material/select'; import { MatTableModule } from '@angular/material/table'; import { ComplianceListRoutingModule } from './compliance-list-routing.module'; @@ -47,17 +36,9 @@ export const MY_FORMATS = { MatInputModule, MatProgressSpinnerModule, MatTableModule, - ReactiveFormsModule, ComplianceListRoutingModule, - MatSelectModule, MatPaginatorModule, - MatDatepickerModule, - MatDialogModule, ], declarations: [ComplianceListComponent], - providers: [ - { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] }, - { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS }, - ], }) export class ComplianceListModule {} diff --git a/otis/src/app/compliance-list/compliance-list.service.ts b/otis/src/app/compliance-list/compliance-list.service.ts index f5c4584..250143c 100644 --- a/otis/src/app/compliance-list/compliance-list.service.ts +++ b/otis/src/app/compliance-list/compliance-list.service.ts @@ -1,4 +1,4 @@ -import { HttpClient, HttpParams } from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/internal/Observable'; import { catchError } from 'rxjs/operators'; @@ -16,13 +16,9 @@ const serviceName = 'ComplianceListService'; export class ComplianceListService { constructor(private http: HttpClient, private log: ErrorLoggerService) {} - list(date: string | null): Observable { - const options = { params: new HttpParams() }; - if (date !== null) { - options.params = options.params.set('d', date); - } + list(): Observable { return this.http - .get(url, options) + .get(url) .pipe(catchError(this.log.handleError(serviceName, 'list'))) as Observable; } } diff --git a/otis/src/app/compliance-list/compliance-list.ts b/otis/src/app/compliance-list/compliance-list.ts index 97b7321..a23e93c 100644 --- a/otis/src/app/compliance-list/compliance-list.ts +++ b/otis/src/app/compliance-list/compliance-list.ts @@ -1,12 +1,20 @@ -import { ComplianceListItem } from './compliance-list-item'; - export class ComplianceList { - date: string; - items: ComplianceListItem[]; + id: string; + officeFileNumber: string; + courtNumber: string; + itemNumber: string; + title: string; + proceedings: string; + complianceDate: string; public constructor(init?: Partial) { - this.date = ''; - this.items = []; + this.id = ''; + this.officeFileNumber = ''; + this.courtNumber = ''; + this.itemNumber = ''; + this.title = ''; + this.proceedings = ''; + this.complianceDate = ''; Object.assign(this, init); } } diff --git a/otis/src/app/core/hearing.ts b/otis/src/app/core/hearing.ts index e2f00e3..11577ef 100644 --- a/otis/src/app/core/hearing.ts +++ b/otis/src/app/core/hearing.ts @@ -8,6 +8,7 @@ export class Hearing { courtStatus: CourtStatus; proceedings: string; complianceDate: string | null; + complianceDone: boolean; nextHearingDate: string | null; public constructor(init?: Partial) { @@ -18,6 +19,7 @@ export class Hearing { this.courtStatus = new CourtStatus(); this.proceedings = ''; this.complianceDate = null; + this.complianceDone = true; this.nextHearingDate = null; Object.assign(this, init); }