Project
authorTomas Zeman <tzeman@volny.cz>
Tue, 24 Apr 2012 20:31:58 +0200
changeset 79 25392159b6ca
parent 78 7af1b5887759
child 80 196896cc3f58
Project
db/db-data.sql
db/db-schema.sql
src/main/scala/bootstrap/liftweb/Boot.scala
src/main/scala/fis/pm/model/PmSchema.scala
src/main/scala/fis/pm/model/Project.scala
src/main/scala/fis/pm/model/ProjectCrud.scala
src/main/scala/fis/pm/ui/ProjectSnippet.scala
src/main/scala/fis/top/model/FisDbSchema.scala
src/main/webapp/templates-hidden/_resources.html
src/main/webapp/templates-hidden/_resources_cs.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/db/db-data.sql	Tue Apr 24 20:31:58 2012 +0200
@@ -0,0 +1,37 @@
+-- Project states
+INSERT INTO code_list_item
+(code_list, id, i18n, name, rank, dflt, i1,
+i2, i3, l1, l2, l3, s1, s2, s3, created_at, updated_at, deleted)
+VALUES
+('project_state', nextval('code_list_item_id_seq'), true, 'project.state.assigned', 10, true, 0,
+0, 0, 0, 0, 0, '', '', '', current_timestamp, current_timestamp, false);
+INSERT INTO code_list_item
+(code_list, id, i18n, name, rank, dflt, i1,
+i2, i3, l1, l2, l3, s1, s2, s3, created_at, updated_at, deleted)
+VALUES
+('project_state', nextval('code_list_item_id_seq'), true, 'project.state.paused', 45, false, 0,
+0, 0, 0, 0, 0, '', '', '', current_timestamp, current_timestamp, false);
+INSERT INTO code_list_item
+(code_list, id, i18n, name, rank, dflt, i1,
+i2, i3, l1, l2, l3, s1, s2, s3, created_at, updated_at, deleted)
+VALUES
+('project_state', nextval('code_list_item_id_seq'), true, 'project.state.in_preparation', 20, false, 0,
+0, 0, 0, 0, 0, '', '', '', current_timestamp, current_timestamp, false);
+INSERT INTO code_list_item
+(code_list, id, i18n, name, rank, dflt, i1,
+i2, i3, l1, l2, l3, s1, s2, s3, created_at, updated_at, deleted)
+VALUES
+('project_state', nextval('code_list_item_id_seq'), true, 'project.state.in_realization', 30, false, 0,
+0, 0, 0, 0, 0, '', '', '', current_timestamp, current_timestamp, false);
+INSERT INTO code_list_item
+(code_list, id, i18n, name, rank, dflt, i1,
+i2, i3, l1, l2, l3, s1, s2, s3, created_at, updated_at, deleted)
+VALUES
+('project_state', nextval('code_list_item_id_seq'), true, 'project.state.cancelled', 50, false, 1,
+0, 0, 0, 0, 0, '', '', '', current_timestamp, current_timestamp, false);
+INSERT INTO code_list_item
+(code_list, id, i18n, name, rank, dflt, i1,
+i2, i3, l1, l2, l3, s1, s2, s3, created_at, updated_at, deleted)
+VALUES
+('project_state', nextval('code_list_item_id_seq'), true, 'project.state.realized', 40, false, 1,
+0, 0, 0, 0, 0, '', '', '', current_timestamp, current_timestamp, false);
--- a/db/db-schema.sql	Tue Mar 06 14:07:55 2012 +0100
+++ b/db/db-schema.sql	Tue Apr 24 20:31:58 2012 +0200
@@ -159,6 +159,22 @@
     "contact" bigint not null,
     "entity" bigint not null
   );
+create table "project" (
+    "name" varchar(100) not null,
+    "updated_at" timestamp not null,
+    "id" bigint primary key not null,
+    "description" varchar(40960) not null,
+    "responsible" bigint not null,
+    "deadline" timestamp not null,
+    "ident_s" varchar(256) not null,
+    "state" bigint not null,
+    "note" varchar(10240),
+    "product_line" bigint,
+    "created_at" timestamp not null,
+    "created_by" bigint,
+    "updated_by" bigint
+  );
+create sequence "project_id_seq";
 -- foreign key constraints :
 alter table "address" add constraint "addressFK1" foreign key ("city_id") references "city"("id");
 alter table "city" add constraint "cityFK2" foreign key ("country_id") references "country"("id");
@@ -166,6 +182,9 @@
 alter table "company" add constraint "companyFK4" foreign key ("address_id") references "address"("id");
 alter table "company" add constraint "companyFK5" foreign key ("post_adress_id") references "address"("id") on delete set null;
 alter table "bank_account" add constraint "bank_accountFK6" foreign key ("company_id") references "company"("id") on delete cascade;
+alter table "project" add constraint "projectFK11" foreign key ("responsible") references "user"("id");
+alter table "project" add constraint "projectFK12" foreign key ("product_line") references "code_list_item"("id") on delete set null;
+alter table "project" add constraint "projectFK13" foreign key ("state") references "code_list_item"("id");
 alter table "company_contact" add constraint "company_contactFK7" foreign key ("entity") references "company"("id") on delete cascade;
 alter table "company_contact" add constraint "company_contactFK8" foreign key ("contact") references "contact"("id") on delete cascade;
 alter table "user_contact" add constraint "user_contactFK9" foreign key ("entity") references "user"("id") on delete cascade;
--- a/src/main/scala/bootstrap/liftweb/Boot.scala	Tue Mar 06 14:07:55 2012 +0100
+++ b/src/main/scala/bootstrap/liftweb/Boot.scala	Tue Apr 24 20:31:58 2012 +0200
@@ -21,6 +21,7 @@
 import fis.aaa.ui._
 import fis.crm.ui._
 import fis.geo.ui._
+import fis.pm.ui._
 import fis.db.SquerylTxMgr
 import net.datatables.DataTables
 import net.liftweb.common._
@@ -58,7 +59,9 @@
       AuthnSnippet.menu,
       CountrySnippet.menu,
       LocationSnippet.menu,
-      CitySnippet.menu)
+      CitySnippet.menu,
+      ProjectSnippet.menu
+    )
 
     LiftRules.setSiteMap(SiteMap(menus:_*))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/fis/pm/model/PmSchema.scala	Tue Apr 24 20:31:58 2012 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012 Tomas Zeman <tzeman@volny.cz>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package fis.pm.model
+
+import fis.aaa.model.AaaSchema
+import fis.base.model.{BaseSchema, Entity}
+import fis.cl.model.CodeListSchema
+import net.liftweb.squerylrecord.RecordTypeMode._
+
+trait PmSchema extends BaseSchema with AaaSchema with CodeListSchema {
+
+  val projectT = tableWithSeq[Project]
+
+  val projectResponsible = oneToManyRelation(userT, projectT).
+    via((u, p) => (u.id === p.responsible))
+
+  val projectProductLine = oneToManyRelation(cli, projectT).
+    via((i, p) => (i.id === p.productLine))
+  projectProductLine.foreignKeyDeclaration.constrainReference(onDelete setNull)
+
+  val projectState = oneToManyRelation(cli, projectT).
+    via((i, p) => (i.id === p.stateFld))
+
+  Project.users.default.set(activeUsersF)
+
+  def projects: Iterable[Project] = from(projectT)(p =>
+    select(p) orderBy(p.name asc))
+}
+
+object PmSchema extends PmSchema
+
+// vim: set ts=2 sw=2 et:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/fis/pm/model/Project.scala	Tue Apr 24 20:31:58 2012 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Tomas Zeman <tzeman@volny.cz>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package fis.pm.model
+
+import fis.aaa.model._
+import fis.base.model.Entity
+import fis.cl.model._
+import net.liftweb.common._
+import net.liftweb.record.{MetaRecord, Record}
+import net.liftweb.record.field._
+import net.liftweb.util._
+import net.tz.lift.model._
+import net.tz.lift.model.{FieldLabel => FL}
+import org.squeryl.annotations.Column
+
+class Project private() extends Record[Project] with Entity[Project] {
+  def meta = Project
+
+  val description = new TextareaField(this, 40960) with FL
+  val identS = new StringField(this, 256) with FL
+  val deadline = new JodaDateMidnightField(this) with FL
+  val productLine = new OptionalCodeListItemField(this, 'product_line) with FL
+  val responsible = new UserField(this, meta.users, getUserVendor) with
+    DefaultCurUser with FL
+
+  @Column("state")
+  protected[pm] val stateFld = new CodeListItemField(this, 'project_state)
+    with FL
+
+  def state = stateFld.item.map { ProjectState(_) }
+}
+
+object Project extends Project with MetaRecord[Project] with SimpleInjector {
+  object users extends Inject[Iterable[User]](() => Nil)
+}
+
+case class ProjectState(id: Long, k: String, closed: Boolean)
+object ProjectState {
+  def apply(i: CodeListItem): ProjectState =
+    ProjectState(i.id, i.name.get, i.i1.get == 1)
+}
+
+// vim: set ts=2 sw=2 et:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/fis/pm/model/ProjectCrud.scala	Tue Apr 24 20:31:58 2012 +0200
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2012 Tomas Zeman <tzeman@volny.cz>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package fis.pm.model
+
+import fis.base.model.RecordCrud
+
+trait ProjectCrud extends RecordCrud[Project] {
+  val table = PmSchema.projectT
+}
+
+object ProjectCrud extends ProjectCrud
+
+// vim: set ts=2 sw=2 et:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/scala/fis/pm/ui/ProjectSnippet.scala	Tue Apr 24 20:31:58 2012 +0200
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2012 Tomas Zeman <tzeman@volny.cz>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package fis.pm.ui
+
+import fis.base.ui._
+import fis.pm.model._
+import net.liftweb.common._
+import net.liftweb.http._
+import net.liftweb.sitemap._
+import net.liftweb.sitemap.Loc._
+import net.liftweb.util._
+import net.liftweb.util.Helpers._
+import net.tz.lift.model._
+import net.tz.lift.snippet._
+import scala.xml.{Elem, NodeSeq, Text}
+
+object ProjectSnippet extends ProjectCrud with EntitySnippet[Project] {
+  val prefix = "project"
+
+  private val listPre = Menu("project.list", l10n("Projects")) / prefix >>
+    Title(_ => i18n("Projects")) >>
+    locTpl("entity/list") >> Snippet("list", list)
+
+  private val createPre = Menu("project.create", l10n("Create")) / prefix / ADD >>
+    Title(_ => i18n("Create project")) >>
+    locTpl("entity/form") >> Snippet("form", form) >> Hidden
+
+  private val viewPre = Menu.param[Project]("project.view", l10n("Project"), parse,
+    encode) / prefix / * >> Title(p => i18n("Project %s", p.linkName)) >>
+    locTpl("entity/view") >> Snippet("panel", panel) >> Hidden
+
+  private val editPre = Menu.param[Project]("project.edit", l10n("Edit"), parse,
+    encode) / prefix / * / EDIT >>
+    Title(p => i18n("Edit project %s", p.linkName)) >>
+    locTpl("entity/form") >> Snippet("form", form) >> Hidden
+
+  private val deletePre = Menu.param[Project]("project.delete", l10n("Delete"),
+    parse, encode) / prefix / * / DELETE >>
+    Title(p => i18n("Delete project %s", p.linkName)) >>
+    locTpl("entity/delete") >> Snippet("form", deleteF) >> Hidden
+
+  private val listM = listPre >> SecNav(createPre).build
+  private val createM = createPre >> SecNav(listPre).build
+  private val viewM = viewPre >> (SecNav(editPre) + deletePre).build
+  private val editM = editPre >> SecNav(viewPre).build
+  private val deleteM = deletePre >> SecNav(viewPre).build
+
+  private lazy val viewLoc = viewM.toLoc
+  private lazy val editLoc = editM.toLoc
+  private lazy val deleteLoc = deleteM.toLoc
+
+  val menu = listM submenus(viewM, editM, createM, deleteM)
+
+  private def cur = viewLoc.currentValue or editLoc.currentValue or
+    deleteLoc.currentValue
+
+  private def list: CssTr = { _ => ProjectTable(PmSchema.projects) }
+
+  private def panel: CssTr = "*" #> cur.map { c => ViewPanel(fields(c)) }
+
+  object url {
+    def view: Project => Box[String] = (viewLoc.calcHref _) andThen (Box !! _)
+  }
+
+  private def fields(p: Project) = List(p.name, p.identS, p.stateFld, p.createdBy,
+    p.createdAt, p.deadline, p.responsible, p.productLine, p.description, p.note)
+
+  private def formFields(p: Project) = List(p.name, p.identS, p.stateFld,
+    p.deadline, p.responsible, p.productLine, p.description, p.note)
+
+  private object ProjectTable extends FieldTable[Project] {
+    def fields(p: Project) = EntityLink(p) ++ Seq(p.identS, p.deadline,
+      p.responsible, p.description, p.note)
+    def apply(l: Iterable[Project]) = build(Project, l)
+  }
+
+  private case class ProjectLink(c: Project) extends EntityLink[Project](c, url.view)
+
+  EntityLink.register[Project](ProjectLink(_))
+
+  private object form extends HorizontalScreen with CancelButton with SaveButton {
+
+    private object project extends ScreenVar[Project](Project.createRecord)
+
+    override def screenFields: List[BaseField] = formFields(project)
+
+    override def localSetup() {
+      cur.foreach(project(_))
+    }
+
+    def finish() { save(project) foreach { v =>
+      S notice l10n("Project %s saved.", v.linkName)
+      S.redirectTo(viewLoc.calcHref(v))
+    }}
+  }
+
+  private object deleteF extends HorizontalScreen with CancelButton with
+    DeleteButton {
+
+    val confirm = field(l10n("Really delete this project?"), false)
+
+    def finish() {
+      for {
+        c <- deleteLoc.currentValue if confirm
+        r <- delete(c)
+        n <- r.box(c.linkName)
+      } {
+        S notice l10n("Project %s deleted.", n)
+        S redirectTo listM.loc.calcDefaultHref
+      }
+    }
+  }
+
+}
+
+// vim: set ts=2 sw=2 et:
--- a/src/main/scala/fis/top/model/FisDbSchema.scala	Tue Mar 06 14:07:55 2012 +0100
+++ b/src/main/scala/fis/top/model/FisDbSchema.scala	Tue Apr 24 20:31:58 2012 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Tomas Zeman <tzeman@volny.cz>
+ * Copyright 2011-2012 Tomas Zeman <tzeman@volny.cz>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,12 +20,14 @@
 import fis.cl.model.CodeListSchema
 import fis.crm.model.CrmSchema
 import fis.geo.model.GeoSchema
+import fis.pm.model.PmSchema
 
 trait FisDbSchema extends BaseSchema
   with CodeListSchema
   with AaaSchema
   with CrmSchema
   with GeoSchema
+  with PmSchema
 
 object FisDbSchema extends FisDbSchema
 
--- a/src/main/webapp/templates-hidden/_resources.html	Tue Mar 06 14:07:55 2012 +0100
+++ b/src/main/webapp/templates-hidden/_resources.html	Tue Apr 24 20:31:58 2012 +0200
@@ -9,6 +9,10 @@
   <res name="Add" lang="en" default="true">Add</res>
   <res name="linkName" lang="en" default="true">Name</res>
   <res name="gps" lang="en" default="true">GPS</res>
+  <res name="createdAt" lang="en" default="true">Created at</res>
+  <res name="createdBy" lang="en" default="true">Created by</res>
+  <res name="updatedAt" lang="en" default="true">Updated at</res>
+  <res name="updatedBy" lang="en" default="true">Updated by</res>
   <!--
     Remove
     Entity type
@@ -174,6 +178,36 @@
   <res name="location.address" lang="en" default="true">Address</res>
 
 
+  <!-- project
+    default strings:
+      Project
+      Projects
+      Create project
+      Project %s
+      Edit project %s
+      Delete project %s
+      Project %s saved.
+      Really delete this project?
+      Project %s deleted.
+  -->
+  <!-- project fields -->
+  <res name="project.name" lang="en" default="true">Name</res>
+  <res name="project.note" lang="en" default="true">Note</res>
+  <res name="project.description" lang="en" default="true">Description</res>
+  <res name="project.identS" lang="en" default="true">Identifier</res>
+  <res name="project.deadline" lang="en" default="true">Deadline</res>
+  <res name="project.productLine" lang="en" default="true">Product line</res>
+  <res name="project.responsible" lang="en" default="true">Responsible</res>
+  <res name="project.stateFld" lang="en" default="true">State</res>
+  <!-- project states -->
+  <res name="project.state.assigned" lang="en" default="true">Assigned</res>
+  <res name="project.state.paused" lang="en" default="true">Paused</res>
+  <res name="project.state.in_preparation" lang="en" default="true">In preparation</res>
+  <res name="project.state.in_realization" lang="en" default="true">In realization</res>
+  <res name="project.state.cancelled" lang="en" default="true">Cancelled</res>
+  <res name="project.state.realized" lang="en" default="true">Realized</res>
+
+
 <!--
   vim: et sw=2 ts=2
 -->
--- a/src/main/webapp/templates-hidden/_resources_cs.html	Tue Mar 06 14:07:55 2012 +0100
+++ b/src/main/webapp/templates-hidden/_resources_cs.html	Tue Apr 24 20:31:58 2012 +0200
@@ -11,6 +11,10 @@
   <res name="gps" lang="cs">GPS</res>
   <res name="Remove" lang="cs">Odebrat</res>
   <res name="Entity type" lang="cs">Typ</res>
+  <res name="createdAt" lang="cs">Vytvořeno</res>
+  <res name="createdBy" lang="cs">Vytvořil</res>
+  <res name="updatedAt" lang="cs">Aktualizováno</res>
+  <res name="updatedBy" lang="cs">Aktualizoval</res>
 
 
   <!-- authn -->
@@ -166,6 +170,34 @@
   <res name="location.address" lang="cs">Adresa</res>
 
 
+  <!-- project -->
+  <res name="Project" lang="cs">Projekt</res>
+  <res name="Projects" lang="cs">Projekty</res>
+  <res name="Create project" lang="cs">Vytvořit projekt</res>
+  <res name="Project %s" lang="cs">Projekt %s</res>
+  <res name="Edit project %s" lang="cs">Upravit projekt %s</res>
+  <res name="Delete project %s" lang="cs">Smazat projekt %s</res>
+  <res name="Project %s saved." lang="cs">Projekt %s uložen.</res>
+  <res name="Really delete this project?" lang="cs">Skutečně smazat projekt?</res>
+  <res name="Project %s deleted." lang="cs">Projekt %s smazán.</res>
+  <!-- project fields -->
+  <res name="project.name" lang="cs">Název</res>
+  <res name="project.note" lang="cs">Poznámka</res>
+  <res name="project.description" lang="cs">Popis</res>
+  <res name="project.identS" lang="cs">Identifikátor</res>
+  <res name="project.deadline" lang="cs">Termín</res>
+  <res name="project.productLine" lang="cs">Produktová řada</res>
+  <res name="project.responsible" lang="cs">Odpovědný</res>
+  <res name="project.stateFld" lang="cs">Stav</res>
+  <!-- project states -->
+  <res name="project.state.assigned" lang="cs">Přidělen</res>
+  <res name="project.state.paused" lang="cs">Pozastaven</res>
+  <res name="project.state.in_preparation" lang="cs">V přípravě</res>
+  <res name="project.state.in_realization" lang="cs">V realizaci</res>
+  <res name="project.state.cancelled" lang="cs">Stornován</res>
+  <res name="project.state.realized" lang="cs">Realizován</res>
+
+
 <!--
   vim: et sw=2 ts=2
 -->