Sử dụng XForms để tạo công cụ kế toán, Phần 5: Phát triển các chức năng quản lý trách nhiệm

Loạt sáu bài này trình bày về cách làm thế nào tận dụng sức mạnh của XForms kết hợp với MySQL và PHP để hỗ trợ tiến trình tạo ra một công cụ kế toán trực tuyến được gọi là X-Trapolate. Tất cả công nghệ lập trình tốt đều xử lý một mảng các bài toán mà nó có thể giải quyết tốt. Loạt bài này nêu bật những vấn đề mà XForms giải quyết một cách hiệu quả, chẳng hạn như nhu cầu về những tính toán trực tuyến và tương tác cao. Phần 5 trong loạt bài sáu phần này mô tả làm thế nào tạo ra biểu mẫu thanh toán cho trách nhiệm pháp lý và thanh toán, và biểu mẫu báo cáo để phân tích dữ liệu thanh toán và thống kê số liệu.

Tyler Anderson, Kỹ sư, Backstop Media

Tyler's photoTyler Anderson đã tốt nghiệp chuyên ngành Khoa học Máy tính tại trường Đại học Brigham Young năm 2004 và hiện đang tham gia học kỳ cuối chương trình đào tạo Thạc sỹ khoa học chuyên ngành Công nghệ Máy tính. Trước đó, anh đã làm việc như là một lập trình viên cơ sở dữ liệu cho DPMG.COM, và hiện tại anh đang là kỹ sư cho tập đoàn Stexar, dựa trên nền tảng Beaverton, Oregon



Stony Yakovac, Kỹ sư phần mềm, 自由职业者

Stony Yakovac là một kỹ sư và là một nhà viết sách tự do, ông đang sống tại Lava Hot Springs, bang Idaho, Hoa Kỳ. Ông làm cho rất nhiều dự án thuộc nhiều lĩnh vực, bao gồm các thiết kế về phần mềm và phần cứng số



10 07 2009

Trước khi bạn bắt đầu

Bài hướng dẫn này dành cho nhà phát triển tìm hiểu cách sử dụng của XForms trong các tình huống thực tế, chứ không phải các ứng dụng "đồ chơi". Nó mô tả cách sử dụng của XForms trong việc tạo ra hai biểu mẫu kế toán khác nhau như là một phần của ứng dụng kế toán X-Tranpolate. Bài hướng dẫn này giả định rằng bạn đã biết được các kiến thức cơ bản về XForms. Sự hiểu biết về kế toán là không bắt buộc.

Giới thiệu về bài viết này

Trong hướng dẫn này, Phần 5 của loạt bài viết gồm sáu phần, thực hiện phát triển bên phía trách nhiệm quản lý của công cụ kế toán, đồng thời với việc điều hành phân tích công cụ tạo ra các bản báo cáo bên phía thanh toán.

Các doanh nghiệp đều có trách nhiệm pháp lý và các khoản thanh toán, vì vậy một công cụ để hỗ trợ quản lý và tạo ra các khoản thanh toán sẽ rất có lợi để theo dõi mọi thứ. Trong hướng dẫn này bạn sẽ thực hiện phát triển một biểu mẫu, được gọi là biểu mẫu thanh toán (payables form), cho phép bạn tạo ra các kiểu khác nhau của các khoản thanh toán và trách nhiệm, bao gồm tiền lương, tiền thưởng, và hóa đơn thanh toán cho các phòng khác nhau trong doanh nghiệp vì thế các thanh toán được ghi có hoặc ghi nợ tới một tài khoản xác định.

Bạn cũng sẽ phát triển một biểu mẫu thứ hai, được gọi là biểu mẫu báo cáo (reports form), để thực hiện phân tích dữ liệu thanh toán và thực hiện thống kê dữ liệu, ví dụ như tổng tiền gửi của khách hàng và tổng giá trị thanh toán không đúng kỳ hạn. Bạn cũng sẽ học cách làm thế nào sử dụng thành phần bind và các thuộc tính calculate của nó để tạo ra kết quả hiển thị báo cáo dưới dạng biểu đồ cột.

Trong hướng dẫn này bạn sẽ nghiên cứu làm thế nào để:

  • Sử dụng bindcalculate để tạo ra hai biểu mẫu
  • Lựa chọn các bản ghi thỏa mãn điều kiện bằng cách sử dụng XPath trong câu lệnh repeat
  • Sử dụng các hộp lựa chọn để chọn các bản ghi có thể thêm, ghi hoặc hủy bỏ

Về loạt bài viết này

Mục đích của loạt bài này là trình bày về tác dụng của XForms trong việc phát triển những ứng dụng Web cũng như cung cấp kiến thức cho người đọc về tác dụng của XForms.

  • Phần 1 là sự giới thiệu tới toàn bộ loạt bài viết tổng quan hoá tất cả các bộ phận của kết quả cuối cùng và những khía cạnh nào có trong mỗi phần trong đặc tả XForms.
  • Phần 2 trình bày về đăng nhập và quản lý tài khoản.
  • Phần 3 trình bày việc phát triển những biểu mẫu gắn liền với việc quản lý tài khoản.
  • Phần 4 tiếp tục trình bày về việc quản lý tài khoản và việc báo cáo những khía cạnh tính toán khác nhau của một doanh nghiệp.
  • Phần 5 trình bày việc quản lý nợ và những cải tiến.
  • Phần 6 kết thúc loạt bài viết với bản tóm tắt các công cụ phát triển, và một vài đề nghị để cải tiến và tiếp tục làm việc với bộ công cụ.

Điều kiện tiên quyết

Hướng dẫn này sử dụng cơ sở dữ liệu MySQL để lưu trữ và tham chiếu dữ liệu. PHPMyAdmin đề nghị được sử dụng đi kèm để định dạng cơ sở dữ liệu MySQL và hiển thị các thực thể từ thực đơn theo giao diện đồ họa.

Mặc dù mục đích của loạt bài viết này là để rèn luyện cho người đọc về cách sử dụng của XForms nên có một số kiến thức nền tảng cần được đề cập đến. Có một số bài báo chất lượng rất tốt và giới thiệu về một loạt khái niệm XForms dựa trên IBM developerWorks (xem tại Tài nguyên). XForms được xây dựng dựa trên XML và vì thế hiểu biết cơ bản về XML cũng là yêu cầu cần thiết.

Các yêu cầu hệ thống

Các phần mềm cần phải có để sử dụng cho hướng dẫn này:

  • Trình duyệt có khả năng hiển thị được XForms ví dụ như Firefox 2.0.1.
  • Máy chủ Web có hỗ trợ PHP ví dụ như WAMP
  • Máy chủ SQL, MySQL, trong trường hợp này đó là một phần trong gói WAMP.

Các khoản phải thanh toán (Payables): dữ liệu

Như đã đề cập trong phần giới thiệu, bạn sẽ tạo ra biểu mẫu thanh toán và các biểu mẫu báo cáo. Trong phần này bạn sẽ tập trung vào XML cái mà sẽ được sử dụng bởi biểu mẫu thanh toán. Đầu tiên bạn sẽ xem sơ đồ dữ liệu của nó, sau đó đến cấu trúc tệp XML thanh toán được sử dụng cho biểu mẫu, dữ liệu mẫu đầu vào XML, và bạn sẽ xem làm thế nào để làm việc với dữ liệu thanh toán XML.

Xem lại lược đồ cơ sở dữ liệu

Biểu mẫu thanh toán sử dụng cơ sở dữ liệu để truy lục dữ liệu có các kiểu khác nhau trong một bản ghi thanh toán. Mã nguồn cho hướng dẫn này là tệp SQL cho phép bạn có thể cập nhật tới cơ sở dữ liệu của bạn để tạo ra bảng bằng câu lệnh SQL trong Ví dụ 1.

Ví dụ 1. Lược đồ thanh toán
DROP TABLE IF EXISTS 'payables';
CREATE TABLE 'payables' (
  'id' int(11) NOT NULL auto_increment,
  'pmtType' varchar(20) NOT NULL,
  'amt' decimal(10,0) NOT NULL,
  'date' date NOT NULL,
  'dept' varchar(40) NOT NULL,
  'desc' varchar(80) NOT NULL,
  'gross' decimal(10,0) NOT NULL,
  'hours' decimal(10,0) NOT NULL,
  'rate' decimal(10,0) NOT NULL,
  'recip' int(11) NOT NULL,
  'recur' int(11) NOT NULL,
  'recurInc' int(11) NOT NULL,
  'recurPer' int(11) NOT NULL,
  PRIMARY KEY  ('id')
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

Trường id là trường khóa, và trường recipacctid của bảng recipient. Tên của các trường còn lại tự giải thích chức năng của chúng, vì thế hãy di chuyển tới phần tiếp theo để học về cấu trúc XML.

Cấu trúc đích

Biểu mẫu thanh toán có cấu trúc XML chứa một danh sách các phòng ban và các khoản phải thanh toán để hiển thị tới biểu mẫu dữ liệu (xem Ví dụ 2).

Ví dụ 2. Cấu trúc XML cho bộ dữ liệu thanh toán
<payablesForm>
  <departments>
    <department name="United Cabinetry" real="1"/>
    <department name="Tables And Chairs" real="1"/>
    <department name="Boxgoods" real="1"/>
    <department name="Blanket Chests" real="1"/>
    <department name="Dressers" real="1"/>
    <department name="Flooring" real="1"/>
    <department name="Custom Flooring" real="1"/>
    <department name="Plank Flooring" real="1"/>
  </departments>
  <payables>
    <payable pmtType="" amt="" date="" dept="" desc="" gross="" 
             hours="" rate="" real="0" recip="" recur="" recurInc="" 
             recurPer="" selected="0"/>
    <payable id="4" pmtType="Wage" amt="120" date="2007-12-31" 
             dept="Boxgoods" desc="New payment" gross="0" hours="0" 
             rate="0" recip="5" recur="1" recurInc="1" recurPer="365" 
             selected="0" real="1">
      <acct acctId="5" firstName="Jaeden" lastName="Arp" 
             username="jaedenarp" password="foo128"
             street="893 East 65th Ln." city="Napoleonville" 
             state="Louisiana" country="USA" zip="24892"
             phone="(645) 847-8741" deptId="0" company="" real="1"/>
    </payable>
    <payable id="6" pmtType="Wage" amt="120" date="2007-12-31" 
             dept="Boxgoods" desc="New payment3" gross="0" hours="0" 
             rate="0" recip="3" recur="1" recurInc="1" recurPer="365" 
             selected="0" real="1">
      <acct acctId="3" firstName="Dexter" lastName="Bullier" 
             username="dexterbullier" password="foo126"
             street="183 NW 79th Ln." city="Coffee Point"
             state="Idaho" country="USA" zip="69320" 
             phone="(109) 611-9170" deptId="0" company="" real="1"/>
    </payable>
  </payables>
</payablesForm>

Trong ví dụ 2 tập hợp các phần tử đầu tiên là các phần tử departments. Mỗi một thanh toán được liên kết tương ứng với một phòng, và người sử dụng sẽ lựa chọn tài khoản thanh toán của phòng nào đó họ muốn hiển thị lên biểu mẫu. Phiếu thanh toán cũng kết nối tương ứng đến một tài khoản, và vì vậy bạn nên chú ý thành phần <acct ...> bên trong các thành phần <payable ...>. Dữ liệu tài khoản được sử dụng để hiển thị thông tin của tài khoản được kết nối đến phiếu thanh toán trong biểu mẫu.

Thuộc tính real của phiếu thanh toán đầu tiên nhận giá trị là 0, điều đó có nghĩa là rằng dữ liệu sẽ không được hiển thị lên biểu mẫu và nó được sử dụng như là khuôn mẫu để thêm một phiếu thanh toán mới trong biểu mẫu.

Tiếp theo, bạn sẽ chú ý đến xử lý cấu trúc XML đầu vào.

Xử lý đầu vào

Dữ liệu mẫu đầu vào của XML phải được khai báo là "biến cục bộ" trong tài liệu XForm để cho phép bạn có thể thực thi và liên kết tới select1 và cho các phần tử đầu vào khác, là các phần tử bạn có thể sử dụng sau đó trong các phần tử bind cho bất kỳ thao tác tính toán nào bạn muốn.

Dữ liệu mẫu đầu vào của XML cho biểu mẫu thanh toán chứa các trường khác nhau có liên quan tới việc đăng nhập vào và các điều khiển khác và các đặc trưng chứa trong toàn bộ biểu mẫu cho phép bạn có thể xem được toàn bộ dữ liệu ban đầu (xem Ví dụ 3).

Ví dụ 3. Dữ liệu mẫu đầu vào tài liệu XML
      <xforms:instance id="atui">
        <atui xmlns="">
          <loginData>
            <loginLogout>Login</loginLogout>
            <password/>
            <login>1</login>
            <loginToken/>
            <username/>
            <deptId/>
            <welcome/>
          </loginData>
          <errorMessage/>
          <refresh/>
          <debug>1</debug>
          <controls>
            <saveSelected/>
            <newPayable/>
            <removePayable/>
            <filters>
              <pmtType>*</pmtType>
              <dept>*</dept>
            </filters>
          </controls>
        </atui>
      </xforms:instance>

Các phần tử dưới <loginData> được liên quan tới việc đăng nhập vào, và các đặc trưng liên quan tới biểu mẫu là nằm dưới <controls>. Có hai phần tử select1 thể hiện danh sách của các kiểu thanh toán và danh sách các department khác, và các nội dung chứa của các phần tử select1 sẽ được lưu giữ trong <pmtType><dept>, cả hai phần tử loại này đều nằm dưới controls/filters. Tiếp theo, đi tìm hiểu làm thế nào dữ liệu mẫu các khoản phải thanh toán được thể hiện.

Sinh ra các phòng ban (departments)

Các phòng ban được sử dụng để sinh ra một thành phần select1, và bạn sẽ thấy cách để sinh ra chúng cho thể hiện XML của các khoản phải thanh toán trong Ví dụ 4.

Ví dụ 4. Sinh ra dữ liệu XML của phòng ban
$query = sprintf('SELECT * FROM `departments`;');
$departmentRows = mysql_query($query, $sqldb);
if (!$departmentRows)
     die ('Could not execute acct db query: <b>'.$query.
          '</b> because:  ' . mysql_error());
while ($departmentRow = mysql_fetch_assoc($departmentRows)) {
   $department = $departmentRow['name'];
   $newDataSrc=$doc->createElement('department');
   $newDataSrc->setAttribute('name',sprintf("%s",$department));
   $newDataSrc->setAttribute('real','1');
   $rootNode->GetElementsByTagName('departments')->
       item(0)->appendChild($newDataSrc);
}

Chú ý rằng dữ liệu đến từ bảng của các phòng ban và sau đó mỗi một phòng được lưu trữ một cách đơn giản dưới dạng một phần tử mới và được thêm vào dữ liệu mẫu. Tiếp theo, tìm hiểu làm thế nào để sinh ra các khoản phải thanh toán.

Sản sinh các khoản phải thanh toán

Khi mà các bản ghi các khoản phải thanh toán được lưu trữ trong cơ sở dữ liệu thì chúng có được khôi phục lại về sau một cách dễ dàng, và trong Ví dụ 5 hiển thị cách làm thế nào để tạo ra dữ liệu mẫu.

Ví dụ 5. Sản sinh các bản ghi các khoản phải thanh toán trong dữ liệu của thể hiện XML
$query = sprintf('SELECT * FROM 'payables';');
$payablesRows = mysql_query($query, $sqldb);
if (!$payablesRows)
    die ('Could not execute acct db query: <b>'.$query.
         '</b> because:  ' . mysql_error());
while ($payablesRow = mysql_fetch_assoc($payablesRows)) {
   $newDataSrc=$doc->createElement('payable');
   foreach ($payablesRow as $key => $val) {
      $newDataSrc->setAttribute($key, $val);
   }
   $newDataSrc->setAttribute('selected','0');
   $newDataSrc->setAttribute('real','1');
   $rootNode->GetElementsByTagName('payables')->
       item(0)->appendChild($newDataSrc);
...
}

Bây giờ các phần tử payable mới được tạo ra bằng cách thêm thuộc tính mới tới bản ghi payable cho các trường chứa trong bảng payables. Có hai thuộc tính trong số các thuộc tính khác cũng được thêm vào, selectedreal; selected=0 chỉ ra rằng nó sẽ không xuất hiện khi được lựa chọn trong biểu mẫu và real=1 chỉ ra rằng nó không phải là phần tử giả và nó là dữ liệu thực được sử dụng trong biểu mẫu. Hãy di chuyển đến bước cuối cùng: Sản sinh các tài khoản.

Sản sinh các tài khoản (accounts)

Phần cuối cùng, tài khoản liên kết cần được thêm như là con tới phần tử <payable> (xem Ví dụ 6).

Ví dụ 6: Sản sinh dữ liệu các tài khoản
...
   $newDataSrc->setAttribute('real','1');
   $rootNode->GetElementsByTagName('payables')->
       item(0)->appendChild($newDataSrc);

   $query = sprintf('SELECT * FROM 'accounts' WHERE '.
                    ''acctId'=%d;',$newDataSrc->GetAttribute('recip'));
   $accountsRows = mysql_query($query, $sqldb);
   if (!$accountsRows) die ('Could not execute acct db query: <b>'.
                            $query.'</b> because:  ' . mysql_error());
   while ($accountsRow = mysql_fetch_assoc($accountsRows)) {
      $newDataSrc2=$doc->createElement('acct');
      foreach ($accountsRow as $key => $val) {
         $newDataSrc2->setAttribute($key, $val);
      }
      $newDataSrc2->setAttribute('real','1');
      $newDataSrc->appendChild($newDataSrc2);
}

Ví dụ 6 cũng giống như khi bạn sản sinh dữ liệu các khoản phải thanh toán trong Ví dụ 5, trừ trường hợp bạn tìm kiếm tài khoản mà ID của nó khớp với acctid được chứa trong recip. Các dòng kết quả từ truy vấn SQL sau đó được thêm vào như là một con của thành phần payable, sẵn sàng cho bạn sử dụng sau này.


Các khoản phải thanh toán: Biểu mẫu

Trong phần này bạn sẽ làm việc với các tài liệu XML mà bạn đã học cách tạo ra nó và đồng thời dùng tài liệu này để cung cấp dữ liệu cho biểu mẫu thanh toán.

Các tính chất cơ bản

Trước tiên bạn sẽ bắt đầu với các hình thức căn bản của biểu mẫu hiển thị trong Ví dụ 7. Đó là nơi mà mọi người sử dụng của X-Trapolate cần phải đăng nhập để tới được biểu mẫu thanh toán.

Ví dụ 7. Các phần cơ bản của biểu mẫu thanh toán
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html 
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xforms="http://www.w3.org/2002/xforms"
   xmlns:ev="http://www.w3.org/2001/xml-events"
   >
  <head>
    <title>Accounting Tool Payables</title>
    
    <xforms:model id="atxm">

      <xforms:instance id="payables">
        <payablesForm xmlns="">
        </payablesForm>
      </xforms:instance>

      <xforms:instance id="atui">
        <atui xmlns="">
          <loginData>
            <loginLogout>Login</loginLogout>
            <password/>
            <login>1</login>
            <loginToken/>
            <username/>
            <deptId/>
            <welcome/>
          </loginData>
          <errorMessage/>
          <refresh/>
          <debug>1</debug>
          <controls>
            <saveSelected/>
            <newPayable/>
            <removePayable/>
            <filters>
              <pmtType>*</pmtType>
              <dept>*</dept>
            </filters>
          </controls>
        </atui>
      </xforms:instance>

      <xforms:bind nodeset="instance('atui')//password"
                   relevant="number(instance('atui')//login)=1"/>
      <xforms:bind nodeset="instance('atui')//username"
                   relevant="number(instance('atui')//login)=1"/>
      <xforms:bind nodeset="instance('atui')//welcome"
                   relevant="instance('atui')//loginLogout = 'Logout'"
                   calculate="concat('Welcome ',
                              instance('atui')//username)"/> 

      <xforms:submission id="login_logout"
                         action="login_logout.php" 
                         method="post"
                         replace="instance" 
                         instance="atui"
                         ref="instance('atui')" />
      
      <xforms:action ev:event="xforms-ready">
        <xforms:dispatch name="xforms-submit" target="login_logout"/>
        <xforms:dispatch name="xforms-submit" target="load_payables"/>
      </xforms:action>

    </xforms:model>
    <style>
      *.required:after { content: "*"; color: red; }
      *.required { font-weight:bold; }
      *.errorMessage { font-weight: bold; color: red; }
    </style>
  </head>
  <body >
    <xforms:input ref="instance('atui')//username">
        <xforms:label>Username:  </xforms:label></xforms:input>
    <xforms:secret ref="instance('atui')//password">
        <xforms:label>Password:  </xforms:label></xforms:secret>
    <xforms:submit submission="login_logout"
        ref="instance('atui')//loginLogout">
        <xforms:label 
            ref="instance('atui')//loginLogout"/></xforms:submit>
    <xforms:output ref="instance('atui')//welcome"/><br/>
    <xforms:output class="errorMessage"
                   value="concat(instance('atui')//errorMessage,
                          instance('queryData')/errorMessage)"/>
...

Trong ví dụ 7 hiển thị bộ ví dụ dữ liệu đầu vào phù hợp với các phần của biểu mẫu như thế nào, và cũng phân chia đăng nhập của biểu mẫu như là đã được sử dụng trong phần trước của loạt bài viết này. Chú ý rằng phần tử action chấp nhận thông tin đăng nhập của người dùng mỗi khi người dùng đăng nhập biểu mẫu. Mỗi khi load_payables được gọi đến thì ngay lập tức biểu mẫu được tải lên và hiển thị với bộ ví dụ ngay trên biểu mẫu. Một số phần tiếp sẽ thêm thân biểu mẫu vào.

Thêm điều kiện chọn lựa thanh toán

Để có thể nhận được nhiều kết quả hữu ích từ biểu mẫu bạn cần phải có khả năng đưa ra các phiếu thanh toán theo từng mục đích riêng lẻ ví dụ như đưa thông tin của phòng Boxgooods và loại thanh toán tiền lương tương ứng. Bạn có nhớ phần tử select1 đã được đề cập? Bạn sẽ thêm chúng vào trong Ví dụ 8.

Ví dụ 8. Lựa chọn các thuộc tính các khoản phải thanh toán
    <table width="100%" border="1px" height="100%">
      <tr height="5%">
        <td width="10%" rowspan="2" valign="top">
          <xforms:select1 
              ref="instance('atui')/controls/filters/pmtType"
              incremental="true()">
            <xforms:label>Payment Type:<br/></xforms:label>
            <xforms:item>
              <xforms:label>Salary</xforms:label>
              <xforms:value>Salary</xforms:value>
            </xforms:item>
            <xforms:item>
              <xforms:label>Wage</xforms:label>
              <xforms:value>Wage</xforms:value>
            </xforms:item>
            <xforms:item>
              <xforms:label>Bill</xforms:label>
              <xforms:value>Bill</xforms:value>
            </xforms:item>
          </xforms:select1>
          <hr/>
          <xforms:select1
              ref="instance('atui')/controls/filters/dept"
              incremental="true()">
            <xforms:label>Department:<br/></xforms:label>
            <xforms:itemset 
                nodeset="instance('payables')/departments//department">
              <xforms:label ref="@name"/>
              <xforms:value ref="@name"/>
            </xforms:itemset>
          </xforms:select1>
        </td>
        <td width="90%">
          <xforms:trigger
              ref="instance('atui')/controls/saveSelected"  
              submission="add_payables">
            <xforms:label>Save/Add Selected Payments</xforms:label>
            <xforms:action ev:event="DOMActivate">
              <xforms:dispatch name="xforms-submit" 
                               target="add_payables"/>
              <xforms:dispatch name="xforms-submit" 
                               target="load_payables"/>
            </xforms:action>
          </xforms:trigger>
          <xforms:trigger ref="instance('atui')/controls/newPayable">
            <xforms:label>Create New Payment</xforms:label>
            <xforms:action ev:event="DOMActivate">
              <xforms:insert nodeset="instance('payables')//payable" 
                         at="count(instance('payables')//payable)-1" 
                         position="after"/>
              <xforms:setvalue
ref="instance('payables')//payable[count(instance('payables')//payable)]/@real"
                  value="1"/>
              <xforms:setvalue 
ref="instance('payables')//payable[count(instance('payables')//payable)]/@id"
                  value="'-1'"/>
              <xforms:setvalue 
ref="instance('payables')//payable[count(instance('payables')//payable)]/@pmtType"
                  value="instance('atui')/controls/filters/pmtType"/>
              <xforms:setvalue 
ref="instance('payables')//payable[count(instance('payables')//payable)]/@dept"
                  value="instance('atui')/controls/filters/dept"/>

            </xforms:action>
          </xforms:trigger>
          <xforms:submit ref="instance('atui')/controls/removePayable" 
                         submission="remove_payables">
            <xforms:label>Remove Selected Payments</xforms:label>
          </xforms:submit>
        </td>
      </tr>

Trước tiên bạn sẽ tìm hiểu làm thế nào hai phần tử select1 đầu tiên được cài đặt. Một cái chứa các thành phần cứng như: *, Wage, SalaryBill. Một cái dùng để khôi phục dữ liệu từ danh sách các phòng ban trong bộ dữ liệu mẫu thanh toán. Tiếp theo là các lựa chọn nút bấm (trigger) và cách giải quyết tương ứng. Chú ý tới lựa chọn nút bấm "Save/Add Selected Payments". Lựa chọn này thực hiện gửi dữ liệu mẫu thanh toán tới tệp PHP cho phép lưu lại các thay đổi và cho phép chèn thêm các dữ liệu mới thông qua thao tác chọn lựa trong hộp danh sách. Sự thay đổi này được tải lại vào trong biểu mẫu tương ứng. Nút bấm "Create New Payment" cho phép tạo ra một phần tử payable mới trong biểu mẫu, khi tạo mới giá trị mặc định của trường ID là -1 (thông tin của bản ghi thanh toán mới được ưu vào cho trường ID của cơ sở dữ liệu), phòng ban của phiếu thanh toán hiện tại là phòng ban hiện tại của phần tử select1, và đồng thời loại thanh toán cho phiếu thanh toán hiện tại được lựa chọn cho các phần tử select1 khác. Thuộc tính real của phần tử này cũng nhận giá trị là 1. Khi thực hiện thao tác với nút cuối cùng cho phép gửi dữ liệu mẫu tới tệp PHP khác để chỉ rằng phần tử lựa chọn được hủy bỏ từ cơ sở dữ liệu. Bạn sẽ nghiên cứu về hai tệp PHP được đề cập đến trong phần sau của vấn đề này.

Danh sách các thành phần đệ trình trong Ví dụ 8 cho các nút lựa chọn ở trên được hiển thị trong Ví dụ 9.

Ví dụ 9. Các phần tử đệ trình
      <xforms:submission id="remove_payables"
                         action="remove_payable.php"
                         method="post"
                         replace="instance"
                         instance="payables"
                         ref="instance('payables')"/>

      <xforms:submission id="add_payables"
                         action="add_payable.php"
                         method="post"
                         ref="instance('payables')"/>
      
      <xforms:submission id="load_payables"
                         action="load_payables.php"
                         method="post"
                         replace="instance"
                         instance="payables"
                         ref="instance('atui')"/>

Chú ý rằng phần tử add_payables chỉ được gửi lên dữ liệu mẫu. Dữ liệu mới được khôi phục bằng cách sử dụng phần tử load_payables.

Tiếp theo bạn di chuyển vào các phần còn lại của biểu mẫu.

Hiển thị phiếu thanh toán

Bây giờ bạn cần phải cung cấp khả năng cho các người dùng X-Trapolate để hiển thị các phiếu thanh toán mà họ đã lựa chọn. Bạn sẽ sử dụng phần tử repeat để cho phép hiển thị dữ liệu có khả năng được trả. Hãy nhìn vào dòng đầu tiên trong Ví dụ 10.

Ví dụ 10. Hiển thị các phiếu có khả năng thanh toán
      <tr>
        <td width="90%">
          <xforms:repeat id="payRpt" 
nodeset="instance('payables')//payable[@real='1'][@pmtType=instance('atui')
/controls/filters/pmtType][@dept=instance('atui')/controls/filters/dept]">
            <table border="1px" width="100%">
              <tr>
                <td rowspan="3" width="5%">
                  <xforms:select appearance="full" ref="@selected">
                    <xforms:item>
                      <xforms:value>1</xforms:value>
                    </xforms:item>
                  </xforms:select>
                </td>
              </tr>
              <tr>
                <td width="95%">
                  <xforms:input ref="@desc">
                      <xforms:label>Description:  </xforms:label>
                  </xforms:input>
                  <xforms:input ref="@amt">
                      <xforms:label>Amount:  </xforms:label>
                  </xforms:input>
                  <xforms:input ref="@date">
                      <xforms:label>Date Due:  </xforms:label>
                  </xforms:input>
                  <xforms:select1 ref="@recurPer">
                    <xforms:label>Frequency:</xforms:label>
                    <xforms:item>
                      <xforms:value>1</xforms:value> 
                      <xforms:label>Daily</xforms:label> 
                    </xforms:item>
                    <xforms:item>
                      <xforms:value>7</xforms:value> 
                      <xforms:label>Weekly</xforms:label> 
                    </xforms:item>
                    <xforms:item>
                      <xforms:value>30</xforms:value> 
                      <xforms:label>Monthly</xforms:label> 
                    </xforms:item>
                    <xforms:item>
                      <xforms:value>90</xforms:value> 
                      <xforms:label>Quarterly</xforms:label> 
                    </xforms:item>
                    <xforms:item>
                      <xforms:value>365</xforms:value> 
                      <xforms:label>Yearly</xforms:label> 
                    </xforms:item>
                  </xforms:select1>
                  <xforms:input ref="@recurInc">
                      <xforms:label>Period: </xforms:label>
                  </xforms:input><br/>
                  <xforms:select appearance="full" ref="@recur">
                    <xforms:item>
                      <xforms:label>Recurring</xforms:label> 
                      <xforms:value>1</xforms:value> 
                    </xforms:item>
                  </xforms:select>
                  <xforms:input ref="@recip">
                      <xforms:label>Payee's account #:  </xforms:label>
                  </xforms:input><br/>
                  Payee's information:
                  <table border="1px"><tr><td>
                        <xforms:output
                            value="concat(acct/@firstName,
                                   ' ',acct/@lastName)"/><br/>
                        <xforms:output value="acct/@street"/><br/>
                        <xforms:output
                            value="concat(acct/@city,', ',acct/@state,
                                   '  ',acct/@zip)"/> <br/>
                  </td></tr></table>
                </td>
              </tr>
            </table>
          </xforms:repeat>
        </td>
      </tr>
    </table>
  </body>
</html>

Phần mới của câu lệnh repeat đó là thuộc tính nodeset hiển thị trong Ví dụ 11.

Ví dụ 11. Thuộc tính nodeset
instance('payables')//payable[@real='1'][@pmtType=instance('atui')
/controls/filters/pmtType][@dept=instance('atui')/controls/filters/dept]

Câu lệnh này lựa chọn tất cả các thành phần thực (@real='1'), và kiểu thanh toán của chúng bằng cái mà đang được chọn trong thành phần select1 khác. Vì vậy, chỉ có các khoản thanh toán phù hợp với kiểu thanh toán và phòng được chọn mới được hiển thị.

Trong thành phần repeat có một hộp kiểm tra cho phép bạn "lựa chọn" từng thành phần. Lựa chọn một thành phần cho phép bạn chỉ ra có hoặc không hủy bỏ một thành phần khỏi cơ sở dữ liệu hoặc lưu/thêm các thay đổi. Dữ liệu của các khoản phải thanh toán sau đó được hiển thị bằng cách sử dụng các thành phần đầu vào, một hộp kiểm, và một thành phần select1. Thông tin liên quan đến các hóa đơn của khoản phải thanh toán sau đó được hiển thị bằng các thành phần đầu ra. Lưu ý rằng chức năng thêm và hủy bỏ sẽ không làm việc cho đến khi bạn xác định mã PHP cho nó, như được giải thích trong phần sau.

Biểu mẫu được hiển thị trong Hình 1.

Hình 1. Biểu mẫu thanh toán
Biểu mẫu thanh toán

Biểu mẫu này có hình thức rất đẹp. Tôi hy vọng rằng bạn sẽ cảm thấy thú vị khi thực hiện làm việc với biểu mẫu. Tiếp theo bạn sẽ đi tìm hiểu làm thế nào PHP thực hiện bổ sung/lưu trữ và hủy bỏ các thanh toán được lựa chọn.

Thêm/Lưu giữ các thanh toán đã chọn

Mỗi khi một thanh toán mới được thêm vào hay một thanh toán nào đó đã có được sửa thì các thanh toán này cần được chọn chế độ làm việc Thêm/Lưu giữ tới cơ sở dữ liệu. PHP cho phép thực hiện các thao tác này được thể hiện rõ trong Ví dụ 12.

Ví dụ 12. Cập nhật các bản ghi đã có và chèn thêm các bản ghi thanh toán mới
$payables = $doc->GetElementsByTagName("payable");
for($i=0;$i < $payables->length;$i++) {
   if ($payables->item($i)->GetAttribute('selected') == 1) {
      $payable = $payables->item($i);

      $id = $payable->GetAttribute('id');
      if($id > 0){ // update
          $query = sprintf("UPDATE 'payables' set 'pmtType' = '%s', 'amt' = '%s', 
'date' = '%s', 'dept' = '%s', 'desc' = '%s', 'gross' = '%s', 'hours' = '%s', 
'rate' = '%s', 'recip' = '%s', 'recur' = '%s', 'recurInc' = '%s', 
'recurPer' = '%s' where 'id' = %d;", 
                           $payable->GetAttribute('pmtType'),
                           $payable->GetAttribute('amt'),
                           $payable->GetAttribute('date'),
                           $payable->GetAttribute('dept'),
                           $payable->GetAttribute('desc'),
                           $payable->GetAttribute('gross'),
                           $payable->GetAttribute('hours'),
                           $payable->GetAttribute('rate'),
                           $payable->GetAttribute('recip'),
                           $payable->GetAttribute('recur'),
                           $payable->GetAttribute('recurInc'),
                           $payable->GetAttribute('recurPer'),
                           $payable->GetAttribute('id'));
          $addQuery = mysql_query($query, $sqldb);
          if (!$addQuery)
              die ('Could not execute acct db query: <b>'.$query.
                   '</b> because:  ' . mysql_error());
      } else { // insert
          $query = sprintf("INSERT INTO 'payables' ( 'id' , 'pmtType' , 
'amt' , 'date' , 'dept' , 'desc' , 'gross' , 'hours' , 'rate' , 'recip' , 'recur' , 
'recurInc' , 'recurPer' ) VALUES ( NULL , '%s', '%s', '%s', '%s', '%s', '%s', '%s', 
'%s', '%s', '%s', '%s', '%s');", 
                           $payable->GetAttribute('pmtType'),
                           $payable->GetAttribute('amt'),
                           $payable->GetAttribute('date'),
                           $payable->GetAttribute('dept'),
                           $payable->GetAttribute('desc'),
                           $payable->GetAttribute('gross'),
                           $payable->GetAttribute('hours'),
                           $payable->GetAttribute('rate'),
                           $payable->GetAttribute('recip'),
                           $payable->GetAttribute('recur'),
                           $payable->GetAttribute('recurInc'),
                           $payable->GetAttribute('recurPer'));
          $addQuery = mysql_query($query, $sqldb);
          if (!$addQuery)
              die ('Could not execute acct db query: <b>'.$query.
                   '</b> because:  ' . mysql_error());
      }
   }
}

Nhận thấy rằng nếu có selected=1 thì có nghĩa hằng hộp thoại lựa chọn đang được chọn điều đó cho phép các bản ghi có thể được lưu trữ/thêm mới tới cơ sở dữ liệu. Nếu id=-1 thì có nghĩa bản ghi thanh toán là bản ghi mới và bản ghi này cần được chèn thêm vào bằng cách sử dụng câu lệnh INSERT hơn là sử dụng câu lệnh UPDATE. Điều ngược lại, khi một bản ghi được cập nhật vào cơ sở dữ liệu thì sẽ phải sử dụng câu lệnh UPDATE.

Tiếp theo, bạn sẽ tìm hiểu làm thế nào để loại bỏ các phần tử trong tình huống tương tự.

Hủy bỏ các phiếu thanh toán được lựa chọn

Khi các thành phần được lựa chọn để hủy bỏ, bộ dữ liệu mẫu cuối cùng được gửi đến PHP như trong Ví dụ 13.

Ví dụ 13. Hủy bỏ các phiếu thanh toán được chọn
$payables = $doc->GetElementsByTagName("payable");
for($i=0;$i < $payables->length;$i++) {
   if ($payables->item($i)->GetAttribute('selected') == 1) {
      $query = sprintf('DELETE FROM 'payables' WHERE 'payables'.'id' '.
              '= %d LIMIT 1;',$payables->item($i)->GetAttribute('id'));
      $removeQuery = mysql_query($query, $sqldb);
      if (!$removeQuery)
          die ('Could not execute acct db query: <b>'.$query.
               '</b> because:  ' . mysql_error());
   }
}
for($i=0;$i < $payables->length;$i++) {
   if ($payables->item($i)->GetAttribute('selected') == 1) {
      $doc->GetElementsByTagName("payables")->
          item(0)->removeChild($payables->item($i));
   }
}
echo $doc->saveXML();

Tương tự như khi thực hiện thêm/lưu giữ các bản ghi thanh toán, ở đây bạn thực hiện duyệt qua tất cả các phiếu thanh toán nếu một cái nào đó được lựa chọn để hủy bỏ thì phiếu thanh toán đó sẽ được hủy bỏ từ cơ sở dữ liệu. Vòng lặp for thứ hai sau khi hủy bỏ hết các phiếu thanh toán được lựa chọn từ cơ sở dữ liệu được gửi trở lại cho biểu mẫu chính để sau này các phiếu này sẽ không được hiển thị lên nữa.

Cuối cùng, sau khi hoàn thành các thao tác với biểu mẫu thanh toán. Tiếp theo bạn sẽ phát triển xây dựng các biểu mẫu báo cáo cho phép bạn thực hiện phân tích dữ liệu thanh toán (từ biểu mẫu thanh toán trong Phần 3 của loạt bài viết này).


Biểu mẫu báo cáo: Dữ liệu

Biểu mẫu báo cáo sẽ được phát triển trong phần này và phần tiếp theo cho phép bạn hiểu thị các tổng kết và các thông tin thống kê (dưới dạng biểu đồ cột) của các hóa đơn thanh toán của công ty. Trước tiên, bạn duyệt qua toàn bộ phần dữ liệu XML được sử dụng bởi biểu mẫu trong phần này.

Cấu trúc đích

Dữ liệu XML ví dụ được sử dụng cho biểu mẫu được lấy từ dữ liệu đã được sử dụng cho biểu mẫu thanh toán trong Phần 3 của loạt bài viết này. Biểu mẫu này về cơ bản tạo ra công cụ phân tích trên các dữ liệu thanh toán cho phép bạn có thể nhìn thấy dưới dạng đồ họa của các tài khoản khác nhau tại các thời điểm (quá khứ đã thanh toán, hiện tại, ...) và đồng thời cũng cho phép có thể thực hiện tổng hợp dữ liệu như là tổng số tiền thanh toán của khách hàng. Chú ý rằng dữ liệu có thể lấy tổng hợp từ một cơ sở dữ liệu khác và khi đó bạn cần tạo thêm các báo cáo dựa trên dữ liệu đã được phân tích. Kiểm tra lại dữ liệu mẫu liên quan trong Ví dụ 14.

Ví dụ 14. Cấu trúc dữ liệu XML mẫu
<?xml version="1.0" encoding="UTF-8"?>
<accounts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <account>
    <acctId>838</acctId>
    <totalDue/>
    <creationDate/>
    <accountState/>
    <bill makeBilURI=""/>
    <pay makeRctURI=""/>
    <paymentAmt/>
    <lastPaymentDate/>
    <minYearCreate/>
    <minMonthCreate/>
    <minDayCreate/>
    <maxYearPaid/>
    <maxMonthPaid/>
    <submitCollection makeDelURI=""/>
    <submitCredit makeCreURI=""/>
    <maxDayPaid/>
    <order>
      <invoiceId>316</invoiceId>
      <acctId>838</acctId>
      <sku>20950</sku>
      <quantity>69</quantity>
      <unitPrice>891.61</unitPrice>
      <discount>0.1421</discount>
      <orderDate>2001-06-26</orderDate>
      <amount/>
      <yearCreate/>
      <monthCreate/>
      <dayCreate/>
    </order>
    <order>
...
    </order>
    <payment>
      <acctId>838</acctId>
      <amount>1310000</amount>
      <paymentDate>2005-06-12</paymentDate>
      <yearPaid/>
      <monthPaid/>
      <dayPaid/>
    </payment>
    <payment>
...
    </payment>

  </account>
  <account>
...
  </account>
</accounts>

Trong phần này bạn có một danh sách các tài khoản với mỗi một tài khoản đều có các thông tin xác định tài khoản tương ứng và các hóa đơn thanh toán phải gắn liền với một tài khoản thanh toán. Tiếp theo, bạn sẽ di chuyển vào dữ liệu đầu vào ví dụ XML.

Xử lý đầu vào

Bộ dữ liệu đầu vào XML cho biểu mẫu này là phức tạp hơn so với các biểu mẫu khác bởi vì có nhiều biến dữ liệu cục bộ được sử dụng để hiển thị trong báo cáo (xem Ví dụ 15).

Ví dụ 15. Tài liệu XML đầu vào
      <xforms:instance id="atui">
        <formui xmlns="">
          <MeasureLabel/>
          <CreditLabel/>
          <PaidLabel/>
          <CurrentLabel/>
          <DueLabel/>
          <PastdueLabel/>
          <DelinquentLabel/>
          <CreditGraph/>
          <PaidGraph/>
          <CurrentGraph/>
          <DueGraph/>
          <PastdueGraph/>
          <DelinquentGraph/>
          <totalAccounts/>
          <percentAccountsCredit/>
          <percentAccountsPaid/>
          <percentAccountsCurrent/>
          <percentAccountsDue/>
          <percentAccountsPastdue/>
          <percentAccountsDelinquent/>
          <zeroPercent>X</zeroPercent>
          <tenPercent>XXXXXXXXXXX</tenPercent>
          <twentyPercent>XXXXXXXXXXXXXXXXXXXXX</twentyPercent>
         <thirtyPercent>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</thirtyPercent>
<fourtyPercent>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</fourtyPercent>
<fiftyPercent>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         </fiftyPercent>
<sixtyPercent>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         </sixtyPercent>
<seventyPercent>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         XXXXXXXXXX</seventyPercent>
<eightyPercent>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         XXXXXXXXXXXXXXXXXXX</eightyPercent>
<ninetyPercent>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         XXXXXXXXXXXXXXXXXXXXXXXXXXXXX</ninetyPercent>
<hundredPercent>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</hundredPercent>
          <billStates>
            <state name="Credit"/>
            <state name="Paid"/>
            <state name="Current"/>
            <state name="Due"/>
            <state name="Pastdue"/>
            <state name="Delinquent"/>
          </billStates>
          <reports>
            <report value="BarGraphAccountStates"
                    name="Graph Account States"
                    label="Graph of Account States (may not add up to 
                     100% due to rounding):"/>
            <report value="AmountCredit"
                    name="Tally Dollar Amount in Customer Credits" 
                    label="Total Credits: $"/>
            <report value="AmountPastDue"
                    name="Tally Dollar Amount Past Due"
                    label="Total Amount Past Due: $"/>
            <report value="AmountDelinquent"
                    name="Tally Dollar Amount Delinquent"
                    label="Total Amount Delinquent: $"/>
          </reports>
          <reportSelector/>
          <tally/>
        </formui>
      </xforms:instance>

Các nhãn, đồ thị và các thành phần phần trăm được sử dụng trong việc tạo một biểu diễn nguyên bản của một đồ thị cột. Với biểu mẫu này đồ thị cột sẽ được biểu diễn bằng cách sử dụng một loạt các X liền nhau. Các thành phần con của các báo cáo chỉ rõ các kiểu có sẵn của các báo cáo. Một cái là đồ thị; ba cái còn lại là dạng tổng. Kiểu hiện tại của báo cáo được lưu trữ trong thành phần reportSelector, và các đầu mục được hiển thị và các kết quả tổng được lưu trữ trong tally, tùy theo giá trị trong reportSelector (kiểu của báo cáo sẽ được xem).

Tiếp theo, bạn sẽ tham gia vào một phần rất thú vị -- tạo biểu mẫu.


Biểu mẫu báo cáo: Biểu mẫu

Biểu mẫu báo cáo cho phép bạn bắt đầu làm việc trong phần tạo báo cáo với XForms. Các thành phần calculate được sử dụng để minh họa khả năng của XForms và các phần tử bind được sử dụng để tạo ra giá trị cuối cùng để hiển thị lên biểu mẫu báo cáo của bạn.

Hiển thị kết quả (Preview)

Hình 2 hiển thị kết quả trình bày của biểu mẫu báo cáo.

Hình 2. Biểu mẫu các báo cáo
reports form

Bây giờ hãy bắt đầu thực hiện mã hóa tạo ra báo cáo.

Các yếu tố cơ bản

Các yếu tố cơ bản tạo thành biểu mẫu báo cáo chính là vị trí để đặt dữ liệu mẫu như trình bày trong Ví dụ 16. Chú ý rằng bạn để làm phần này tốt bạn nên tìm hiểu các câu lệnh bind tử biểu mẫu thanh toán trong Phần 3 của loạt bài viết này. Các thành phần bind và các kết quả tính toán cần thiết của biểu mẫu báo cáo đã được thực hiện trong biểu mẫu thanh toán ở phần trước.

Ví dụ 16. Biểu mẫu phân tích cơ bản
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
          "http://www.w3.org/TR/xhtml1/D/tdxhtml1-strict.dtd">
<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xforms="http://www.w3.org/2002/xforms" 
   xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   >

  <head>
    <title>XForms Accounting Billing Analysis</title>
    <link rel="stylesheet" href="style.css" type="text/css"/>
    <style type="text/css">
      textarea { font-family: sans-serif; height: 1.2em; width: 90%; }
    </style>
    <xforms:model id="acctToolAnalyzeModel" >

      <xforms:instance id="atui">
        <formui xmlns="">
          <queryBilling/>
          <startDate/>
          <endDate/>
          <saveBilling/>
          <MeasureLabel/>
          <CreditLabel/>
          <PaidLabel/>
          <CurrentLabel/>
...
        </formui>
      </xforms:instance>

      <xforms:instance id="analyze" src="analyze_small.xml">
        <accounts xmlns=""/>
      </xforms:instance>

      <xforms:submission id="load_accts"
                         action="get_analyze_data.php"
                         method="get"
                         replace="instance" instance="analyze"
                         ref="instance('atui')" />

      <xforms:bind nodeset="instance('analyze')//order/yearCreate"             
                   calculate="substring(../orderDate, 1, 4)"/>
      <xforms:bind nodeset="instance('analyze')//minYearCreate"                
                   calculate="min(..//yearCreate)"/>
      <xforms:bind nodeset="instance('analyze')//order/monthCreate"            
                   calculate="if(../yearCreate = ../../minYearCreate,number(substring
(../orderDate, 6, 2)),13)"/>
      <xforms:bind nodeset="instance('analyze')//minMonthCreate"               
                   calculate="min(..//order/monthCreate)"/>
      <xforms:bind nodeset="instance('analyze')//order/dayCreate"              
                   calculate="if(../monthCreate = ../../minMonthCreate,number(substring
(../orderDate, 9, 2)),32)"/>
      <xforms:bind nodeset="instance('analyze')//minDayCreate"                 
                   calculate="min(..//order/dayCreate)"/>
      <xforms:bind nodeset="instance('analyze')//creationDate"                 
                   calculate="concat(../minYearCreate,
                   '-',
                   if(../minMonthCreate < 10,
                   concat('0',../minMonthCreate),
                   ../minMonthCreate),
                   '-',
                   if(../minDayCreate < 10,
                   concat('0',../minDayCreate),
                   ../minDayCreate))"/>

      <xforms:bind nodeset="instance('analyze')//payment/yearPaid"             
                   calculate="substring(../paymentDate, 1, 4)"/>
      <xforms:bind nodeset="instance('analyze')//maxYearPaid"                  
                   calculate="max(..//yearPaid)"/>
      <xforms:bind nodeset="instance('analyze')//payment/monthPaid"            
                   calculate="if(../yearPaid = ../../maxYearPaid,number(substring
(../paymentDate, 6, 2)),0)"/>
      <xforms:bind nodeset="instance('analyze')//maxMonthPaid"                 
                   calculate="max(..//payment/monthPaid)"/>
      <xforms:bind nodeset="instance('analyze')//payment/dayPaid"              
                   calculate="if(../monthPaid = ../../maxMonthPaid,number(substring
(../paymentDate, 9, 2)),0)"/>
      <xforms:bind nodeset="instance('analyze')//maxDayPaid"                   
                   calculate="max(..//payment/dayPaid)"/>
      <xforms:bind nodeset="instance('analyze')//lastPaymentDate"              
                   calculate="concat(../maxYearPaid,
                   '-',
                   if(../maxMonthPaid < 10,
                   concat('0',../maxMonthPaid),
                   ../maxMonthPaid),
                   '-',
                   if(../maxDayPaid < 10,
                   concat('0',../maxDayPaid),
                   ../maxDayPaid))"/>

      <xforms:bind nodeset="instance('analyze')//order/amount"                 
                   calculate="../quantity * ../unitPrice * (1-../discount)"/>
      <xforms:bind nodeset="instance('analyze')//totalDue"                     
                   calculate="round(sum(..//order/amount) - sum
                                           (..//payment/amount))"/>
      <xforms:bind nodeset="instance('analyze')//accountState"                 
                   calculate="if(number(../totalDue)>0,
                   if(days-from-date(now()) - if(../maxYearPaid='NaN',
                   days-from-date(../creationDate),
                   days-from-date(../lastPaymentDate)) > 30,
                   if(days-from-date(now()) - if(../maxYearPaid='NaN',
                   days-from-date(../creationDate),
                   days-from-date(../lastPaymentDate)) > 90,
                   if(days-from-date(now()) - if(../maxYearPaid='NaN',
                   days-from-date(../creationDate),
                   days-from-date(../lastPaymentDate)) > 180,
                   'Delinquent',
                   'Pastdue'),
                   'Due'),
                   'Current'),
                   if(number(../totalDue)<0,
                   'Credit',
                   'Paid'))"/>

      <xforms:bind nodeset="instance('analyze')//submitCollection"             
                   relevant="../accountState = 'Delinquent'"/>
      <xforms:bind nodeset="instance('analyze')//submitCredit"                 
                   relevant="../accountState = 'Credit'"/>

      <xforms:bind nodeset="instance('atui')//tally" calculate= 
                   "if(../reportSelector='BarGraphAccountStates', 
                   '', 
                   if(../reportSelector='AmountCredit', 
           sum(instance('analyze')//totalDue[../accountState='Credit'])
               *number('-1'),
                   if(../reportSelector='AmountDelinquent', 
sum(instance('analyze')//totalDue[../accountState='Delinquent']),
                   if(../reportSelector='AmountPastDue', 
sum(instance('analyze')//totalDue[../accountState='Pastdue']), ''))))"/>

Tệp analyze_small.xml chứa một số dữ liệu kiểm tra cho bạn, bạn có thể sử dụng để kiểm tra và sửa lỗi khi tạo biểu mẫu của bạn. Phần còn lại của các thành phần bind, calculate và các thành phần liên quan đã được đề cập trong biểu mẫu hóa đơn trong Phần 3 của loạt bài này, trừ một cái, tally. Nội dung của các thành phần này thay đổi phụ thuộc vào giá trị của reportSelector, thành phần select1 lưu trữ kết quả mà báo cáo yêu cầu. Chú ý rằng điều này chỉ kích hoạt cho ba báo cáo tổng hợp. Nếu lựa chọn AmountCredit được chọn thì khi đó tổng số các hóa đơn thanh toán cho từng tài khoản sẽ được tính tổng và được hiển thị trong thành phần tally. Biểu đồ cột dược sử dụng mặc định cho kiểu báo cáo đầu tiên và bạn sẽ thấy trong phần tiếp theo.

Thân biểu mẫu

Thân của biểu mẫu chứa các phần tử để hiển thị lên biểu mẫu từ các báo các (Ví dụ 17).

Ví dụ 17. Thân biểu mẫu
    </xforms:model>
  </head>
  
  <body>
   Note the behind the scenes PHP in this XForm uses the SQL data and tables for the 
Billing XForm in Part 3 of this series.<br/>
    <xforms:submit submission="load_accts" ref="instance('atui')/queryBilling">
      <xforms:label>Refresh/load Billing Data</xforms:label>
    </xforms:submit>
    <hr/>

    <xforms:select1 ref="instance('atui')/reportSelector" 
                    incremental="true()">
      <xforms:label>Choose report type: </xforms:label>
      <xforms:itemset nodeset="instance('atui')/reports/report">
        <xforms:label ref="@name"/>
        <xforms:value ref="@value"/>
      </xforms:itemset>
    </xforms:select1><br/><br/><br/>

    <xforms:output 
value="instance('atui')//report[@value=instance('atui')/reportSelector]
    /@label"/><xforms:output ref="instance('atui')//tally"/><br/>
<pre>
<xforms:output value="instance('atui')//MeasureLabel"/>
<xforms:output value="instance('atui')//CreditLabel"/>
              <xforms:output value="instance('atui')//CreditGraph"/>

<xforms:output value="instance('atui')//PaidLabel"/>
              <xforms:output value="instance('atui')//PaidGraph"/>

<xforms:output value="instance('atui')//CurrentLabel"/>
              <xforms:output value="instance('atui')//CurrentGraph"/>

<xforms:output value="instance('atui')//DueLabel"/>
              <xforms:output value="instance('atui')//DueGraph"/>

<xforms:output value="instance('atui')//PastdueLabel"/>
              <xforms:output value="instance('atui')//PastdueGraph"/>

<xforms:output value="instance('atui')//DelinquentLabel"/>
              <xforms:output 
                  value="instance('atui')//DelinquentGraph"/>

</pre>
  </body>
</html>

Tương đối đơn giản! Đa số không hiển thị ngay lúc đầu, và dữ liệu đồ thị dạng cột sẽ chỉ hiển thị nếu báo cáo đó được chọn trong thành phần select1. Đồ thị cột được hiển thị trong các thẻ <pre> sao cho các biểu đồ cột sắp xếp với chỉ số đo (0% tới 100% -- bạn sẽ thấy ý nghĩa của nó khi xem Hình 2). Các nhãn của biểu đồ được hiển thị bên trong các thẻ <pre> và trong các phần tiếp theo sẽ tìm kiểu cách làm thế nào để cài đặt các nhãn đó.

Cài đặt các nhãn biểu đồ cột

Như hiển thị trong Ví dụ 18, các giá trị: CreditLabel, PaidLabel, ..., là các thuộc tính calculate của các thành phần bind cho từng dữ liệu mẫu của các nhãn biểu đồ và chúng cần cài đặt tới các trường thích hợp mỗi khi biểu đồ cột được lựa chọn (xem Ví dụ 18)

Ví dụ 18.Cài đặt các nhãn biểu đồ cột
      <xforms:bind nodeset="instance('atui')//MeasureLabel" 
calculate="if(../reportSelector='BarGraphAccountStates',concat(
'              0%       10%       20%       30%       40%       50%',
'       60%       70%       80%       90%      100%'),'')"/>
      <xforms:bind nodeset="instance('atui')//CreditLabel" 
calculate="if(../reportSelector='BarGraphAccountStates','Credit','')"/>
      <xforms:bind nodeset="instance('atui')//PaidLabel" 
calculate="if(../reportSelector='BarGraphAccountStates','Paid','')"/>
      <xforms:bind nodeset="instance('atui')//CurrentLabel" 
calculate="if(../reportSelector='BarGraphAccountStates','Current',
'')"/>
      <xforms:bind nodeset="instance('atui')//DueLabel" 
calculate="if(../reportSelector='BarGraphAccountStates','Due','')"/>
      <xforms:bind nodeset="instance('atui')//PastdueLabel" 
calculate="if(../reportSelector='BarGraphAccountStates',
'Past Due','')"/>
      <xforms:bind nodeset="instance('atui')//DelinquentLabel" 
calculate="if(../reportSelector='BarGraphAccountStates','Delinquent',
'')"/>

Tiếp theo, bạn sẽ tính tổng số và các phần trăm cho đồ thị cột.

Tính tổng số và phần trăm

Điều cuối cùng cần làm là tính tổng số các tài khoản (số các thành phần account trong thể hiện dữ liệu, như trong Ví dụ 14), và sau đó đặt mỗi phần trăm cho từng phần của đồ thị (xem Ví dụ 19).

Ví dụ 19. Đặt dữ liệu đồ thị
      <xforms:bind nodeset="instance('atui')//totalAccounts" 
                   calculate="count(instance('analyze')//account)"/>
      <xforms:bind nodeset="instance('atui')//percentAccountsCredit" 
calculate="count(instance('analyze')//account[accountState='Credit']) 
           div ../totalAccounts * 100"/>
      <xforms:bind nodeset="instance('atui')//percentAccountsPaid" 
calculate="count(instance('analyze')//account[accountState='Paid'])
           div ../totalAccounts * 100"/>
      <xforms:bind nodeset="instance('atui')//percentAccountsCurrent" 
calculate="count(instance('analyze')//account[accountState='Current']) 
           div ../totalAccounts * 100"/>
      <xforms:bind nodeset="instance('atui')//percentAccountsDue" 
calculate="count(instance('analyze')//account[accountState='Due'])
           div ../totalAccounts * 100"/>
      <xforms:bind nodeset="instance('atui')//percentAccountsPastdue" 
calculate="count(instance('analyze')//account[accountState='Pastdue'])
           div ../totalAccounts * 100"/>
      <xforms:bind 
          nodeset="instance('atui')//percentAccountsDelinquent"  
          calculate=
     "count(instance('analyze')//account[accountState='Delinquent'])
           div ../totalAccounts * 100"/>

Đầu tiên, bạn đã thống kê được tổng số tiền của các tài khoản thông qua trường totalAccounts. Sau đó mỗi nhóm gồm sáu kiểu trạng thái tài khoản, bạn sẽ tính tổng tất cả lại rồi chia cho tổng số các tài khoản và nhân với 100 để thu được tỷ lệ phần trăm tương ứng. Sau đó các kết quả này được hiển thị lên biểu đồ.

Tính toán biểu đồ

Bây giờ bạn đã có các tỷ lệ phần trăm bạn có thể đặt các giá trị đó để hiển thị lên biểu đồ. Bạn sẽ có 11 vạch chia trên biểu đồ đó là các giá trị: không, mười, hai mươi, ba mươi, bốn mươi, năm mươi, sáu mươi, bảy mươi, tám mươi, chính mươi và một trăm phần trăm. Chú ý rằng rằng có thể có xảy ra lỗi làm tròn ví dụ như dữ liệu sẽ không lên đến 100 nhưng có thể vượt quá 100 trong hầu hết các trường hợp khi làm việc với tập dữ liệu lớn. Xem cách đặt các vạch chia này như thế nào trong Ví dụ 20.

Ví dụ 20. Cài đặt dữ liệu hiển thị trong biểu đồ
      <xforms:bind nodeset="instance('atui')//CreditGraph" 
          calculate="if(../reportSelector!='BarGraphAccountStates','',
if(../percentAccountsCredit <= 0, ../zeroPercent,
if(../percentAccountsCredit <= 10, ../tenPercent,
if(../percentAccountsCredit <= 20, ../twentyPercent,
if(../percentAccountsCredit <= 30, ../thirtyPercent,
if(../percentAccountsCredit <= 40, ../fortyPercent,
if(../percentAccountsCredit <= 50, ../fiftyPercent,
if(../percentAccountsCredit <= 60, ../sixtyPercent,
if(../percentAccountsCredit <= 70, ../seventyPercent,
if(../percentAccountsCredit <= 80, ../eightyPercent,
if(../percentAccountsCredit <= 90, ../ninetyPercent,
../hundredPercent)))))))))))"/>

      <xforms:bind nodeset="instance('atui')//PaidGraph" 
          calculate="if(../reportSelector!='BarGraphAccountStates','',
if(../percentAccountsPaid <= 0, ../zeroPercent,
if(../percentAccountsPaid <= 10, ../tenPercent,
if(../percentAccountsPaid <= 20, ../twentyPercent,
if(../percentAccountsPaid <= 30, ../thirtyPercent,
if(../percentAccountsPaid <= 40, ../fortyPercent,
if(../percentAccountsPaid <= 50, ../fiftyPercent,
if(../percentAccountsPaid <= 60, ../sixtyPercent,
if(../percentAccountsPaid <= 70, ../seventyPercent,
if(../percentAccountsPaid <= 80, ../eightyPercent,
if(../percentAccountsPaid <= 90, ../ninetyPercent,
../hundredPercent)))))))))))"/>

      <xforms:bind nodeset="instance('atui')//CurrentGraph" 
          calculate="if(../reportSelector!='BarGraphAccountStates','',
if(../percentAccountsCurrent <= 0, ../zeroPercent,
if(../percentAccountsCurrent <= 10, ../tenPercent,
if(../percentAccountsCurrent <= 20, ../twentyPercent,
if(../percentAccountsCurrent <= 30, ../thirtyPercent,
if(../percentAccountsCurrent <= 40, ../fortyPercent,
if(../percentAccountsCurrent <= 50, ../fiftyPercent,
if(../percentAccountsCurrent <= 60, ../sixtyPercent,
if(../percentAccountsCurrent <= 70, ../seventyPercent,
if(../percentAccountsCurrent <= 80, ../eightyPercent,
if(../percentAccountsCurrent <= 90, ../ninetyPercent,
../hundredPercent)))))))))))"/>

      <xforms:bind nodeset="instance('atui')//DueGraph" 
          calculate="if(../reportSelector!='BarGraphAccountStates','',
if(../percentAccountsDue <= 0, ../zeroPercent,
if(../percentAccountsDue <= 10, ../tenPercent,
if(../percentAccountsDue <= 20, ../twentyPercent,
if(../percentAccountsDue <= 30, ../thirtyPercent,
if(../percentAccountsDue <= 40, ../fortyPercent,
if(../percentAccountsDue <= 50, ../fiftyPercent,
if(../percentAccountsDue <= 60, ../sixtyPercent,
if(../percentAccountsDue <= 70, ../seventyPercent,
if(../percentAccountsDue <= 80, ../eightyPercent,
if(../percentAccountsDue <= 90, ../ninetyPercent,
../hundredPercent)))))))))))"/>

      <xforms:bind nodeset="instance('atui')//PastdueGraph" 
          calculate="if(../reportSelector!='BarGraphAccountStates','',
if(../percentAccountsPastdue <= 0, ../zeroPercent,
if(../percentAccountsPastdue <= 10, ../tenPercent,
if(../percentAccountsPastdue <= 20, ../twentyPercent,
if(../percentAccountsPastdue <= 30, ../thirtyPercent,
if(../percentAccountsPastdue <= 40, ../fortyPercent,
if(../percentAccountsPastdue <= 50, ../fiftyPercent,
if(../percentAccountsPastdue <= 60, ../sixtyPercent,
if(../percentAccountsPastdue <= 70, ../seventyPercent,
if(../percentAccountsPastdue <= 80, ../eightyPercent,
if(../percentAccountsPastdue <= 90, ../ninetyPercent,
../hundredPercent)))))))))))"/>

      <xforms:bind nodeset="instance('atui')//DelinquentGraph" 
          calculate="if(../reportSelector!='BarGraphAccountStates','',
if(../percentAccountsDelinquent <= 0, ../zeroPercent,
if(../percentAccountsDelinquent <= 10, ../tenPercent,
if(../percentAccountsDelinquent <= 20, ../twentyPercent,
if(../percentAccountsDelinquent <= 30, ../thirtyPercent,
if(../percentAccountsDelinquent <= 40, ../fortyPercent,
if(../percentAccountsDelinquent <= 50, ../fiftyPercent,
if(../percentAccountsDelinquent <= 60, ../sixtyPercent,
if(../percentAccountsDelinquent <= 70, ../seventyPercent,
if(../percentAccountsDelinquent <= 80, ../eightyPercent,
if(../percentAccountsDelinquent <= 90, ../ninetyPercent,
../hundredPercent)))))))))))"/>

    </xforms:model>
  </head>

Biểu mẫu đã hoàn toàn được tạo ra đầy đủ yêu cầu. Kết quả bạn sẽ có được biểu đồ cột hiển thị tỷ lệ của các khách hàng với các thông tin liên quan gồm ghi có, đã trả đầy đủ, hiện hành, nợ, nợ quá hạn, và người trả nợ không đúng hạn.


Tổng kết

Chúc mừng bạn đã hoàn thành Phần 5 trong loạt bài này. Bạn có đầy đủ các chức năng liên quan đến thanh toán và các báo cáo tương ứng. Bạn có thể áp dụng để theo dõi các khoản nợ của công ty bạn. Đối với việc lập báo cáo bạn có thể mở rộng thêm một số chức năng bằng cách đưa thêm các loại mẫu báo cáo khác hoặc có thể sử dụng giao diện đồ họa SVG để giải quyết.

Bây giờ hãy chuyển tới phần cuối cùng trong Phần 6 để bạn có thể thấy được làm thế nào tích hợp tất cả các biểu mẫu tương ứng với chức năng khi đăng nhập.


Tải về

Mô tảTênKích thước
Part 5 sample codeaccttool_part5_source.zip14KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

  • XForms Recomendation được duy trì bởi W3C.
  • Tải MozzIE, là điều khiển mã nguồn mở cho phép bạn có thể diễn tả được XForms trên trình duyệt Internet Explorer.

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=407875
ArticleTitle=Sử dụng XForms để tạo công cụ kế toán, Phần 5: Phát triển các chức năng quản lý trách nhiệm
publish-date=07102009