FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour Unicode GET cannot be highlighted
Posts: 24
Joined: Wed Oct 15, 2008 01:04 PM
Unicode GET cannot be highlighted
Posted: Thu Nov 27, 2025 07:56 AM

I am using FWH 19.12.

I found that in GET field and it is Unicode, the characters cannot be highlighted by SHIFT+arrowkeys, only by mouse selection. If the field is ANSI, highlight is OK. Have it be solved in new FWH version?

In new version sample programs, is there a program like YUNUS.PRG but using MariaDB? Is there a sample program to explain all the power of Xbrowse (eg. different sorting seq, searching by value, save JPG to database, drop files, etc.)?

Thanks.

Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: Unicode GET cannot be highlighted
Posted: Thu Nov 27, 2025 11:27 AM

Dear Max,

Lets migrate yunus.prg to use MariaDB:

  1. We install and execute xampp, then we start Apache and MySQL. Then using the internet browser
    we go to localhost/phpmyadmin. We manually create a fwh database and create a user. In our example
    we use fivetec1_antonio as the user name.

  2. We migrate the DBFs to MariaDB using modified samples\maria06.prg:

Modified maria06.prg

#include "FiveWin.ch"

REQUEST DBFCDX
REQUEST HB_LANG_ES
REQUEST HB_CODEPAGE_ESWIN

//----------------------------------------------------------------------------//

function Main()

   local oCn, oRs
   local cLog  := cFileSetExt( ExeName(), "log" )

   FErase( cLog )

   RDDSETDEFAULT( "DBFCDX" )
   SET DELETED ON
   SET DATE ITALIAN
   SET CENTURY ON

   HB_CDPSELECT("ESWIN")
   HB_LangSelect( "ES" )

   FW_SetUnicode( .f. )

   oCn := maria_Connect( "localhost", "fwh", "fivetec1_antonio", "1234" )  

   ocn:lLogErr := .t.

   ocn:ImportFromDbf( "invoices.dbf",,,,,,"utf8_spanish2_ci" )

   oRs   := oCn:RowSet( "invoices" )
   XBROWSER oRs FASTEDIT AUTOSORT

   oCn:Close()

   if File( cLog )
      WinExec( "notepad.exe " + cLog )
   endif

return nil

We repeat the process for items.dbf, invitems.dbf and clients2.dbf.

if everything worked as expected then we can see our new MariaDB tables in database fwh from localhost/phpmyadmin

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: Unicode GET cannot be highlighted
Posted: Thu Nov 27, 2025 11:32 AM

Next we modify yunus.prg function OpenDataBases() this way:

static function OpenDataBases()  

   local oCn := maria_Connect( "localhost", "fwh", "fivetec1_antonio", "1234" )  
     

   if oCn == nil  

      MsgStop( "Error connecting to the DataBase" )  

      return nil  

   endif  
     

return oCn
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: Unicode GET cannot be highlighted
Posted: Thu Nov 27, 2025 12:18 PM

Here you have an initial version of yunusm.prg. Copy yunus.rc to yunusm.rc.

You can use items and clients by now. We are working to complete invoices.

yunusm.prg

#include "FiveWin.ch"
#include "easyrep.ch"

REQUEST DBFCDX

static oWndMain, oWndInvoices, oWndClients, oWndItems
static aBlankItem
static cItemFlds  := "INVNUM,SERIAL,ITEMCODE,ITEMNAME,QUANTITY,UNIT,PRICE,DISCOUNT,RECNO()"
static nTaxRate   := 0.0
static oCn

//----------------------------------------------------------------------------//

function Main()

   local oBrush, oFont

   OpenDataBases()

   DEFINE BRUSH oBrush RESOURCE "background"
   DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-12

//   SetDlgGradient( { { 1, RGB( 199, 216, 237 ), RGB( 237, 242, 248 ) } } )

   DEFINE WINDOW oWndMain TITLE "Invoicing" MDI MENU BuildMenu() VSCROLL HSCROLL BRUSH oBrush
   oWndMain:SetFont( oFont )

   BuildMainBar()

   DEFINE MSGBAR PROMPT "Invoicing app" ;
      OF oWndMain 2007 KEYBOARD DATE

   ACTIVATE WINDOW oWndMain MAXIMIZED

   RELEASE BRUSH oBrush

return nil

//----------------------------------------------------------------------------//

INIT PROCEDURE inv_init

   SET DATE BRITISH
   SET CENTURY ON
   SET EPOCH TO ( YEAR( DATE() ) - 50 )

   RDDSETDEFAULT( "DBFCDX" )
   SET DELETED ON

   SetGetColorFocus()

return

//----------------------------------------------------------------------------//

static function BuildMainBar()

   local oBar

   DEFINE BUTTONBAR oBar OF oWndMain 2007 SIZE 70, 60 //70

   DEFINE BUTTON OF oBar PROMPT "Invoices" RESOURCE "code" ;
      ACTION Invoices()

   DEFINE BUTTON OF oBar PROMPT "Clients" RESOURCE "clients" ;
      ACTION Clients()

   DEFINE BUTTON OF oBar PROMPT "Items" RESOURCE "relation" ;
      ACTION Items()

   DEFINE BUTTON OF oBar PROMPT "Exit" RESOURCE "exit" ;
      ACTION oWndMain:End()

return nil

//----------------------------------------------------------------------------//

static function BuildMenu()

   local oMenu

   MENU oMenu

  MENUITEM "Tasks"
  MENU
     MENUITEM "Invoices" ACTION Invoices()
     //MENUITEM "Invoices items" ACTION ( "invitems" )->( XBrowse() )
     MENUITEM "Clients"  ACTION Clients()
     MENUITEM "Items"    ACTION Items()
     SEPARATOR
     MENUITEM "Exit" ACTION oWndMain:End()
  ENDMENU

  oMenu:AddMDI()
  oMenu:AddHelp( "Invoicing app", "(c) FiveTech Software" )

   ENDMENU

return oMenu

//----------------------------------------------------------------------------//

static function Clients()

   local oBrw, cClrBack, cAlias, oRs
   local oBar, oMsgBar, oMsgDeleted

   if oWndClients == nil
      oRs = oCn:RowSet( "SELECT * FROM clients2 ORDER BY code" )

  DEFINE WINDOW oWndClients MDICHILD OF oWndMain TITLE "Clients"

  @ 2, 0 XBROWSE oBrw OF oWndClients LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRs NOBORDER

  oBar  := BrwBtnBar( @oBrw, oWndClients )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION oBrw:Report( "Clients report",, .F.)

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndClients:End()

  cAlias = Alias()

  BrwColors( oBrw )
  // BrwRecSel( oBrw, "RECNO" )

  oBrw:bEdit  := { |oRec| EditClients( oRec ) }

  oBrw:CreateFromCode()
  oBrw:SetFocus()
  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }

  oWndClients:oClient = oBrw
  oWndClients:oControl = oBrw

  DEFINE MSGBAR oMsgBar OF oWndClients 2007

  ACTIVATE WINDOW oWndClients MAXIMIZED ;
     VALID ( oWndClients := nil, .T. )
   else
      oWndClients:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function Items()

   local oBrw, cClrBack
   local oBar, oMsgBar, oMsgDeleted, oRs

   if oWndItems == nil
      oRs = oCn:RowSet( "SELECT * FROM items ORDER BY code" )

  DEFINE WINDOW oWndItems MDICHILD OF oWndMain TITLE "Items"

  @ 2, 0 XBROWSE oBrw OF oWndItems LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRs NOBORDER

  oBar  := BrwBtnBar( @oBrw, oWndItems )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION oBrw:Report( "Items report",, .F.)

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndItems:End()
  BrwColors( oBrw )
  // BrwRecSel( oBrw, "RECNO" )

  oBrw:bEdit  := { |oRec| EditItems( oRec ) }

  oBrw:CreateFromCode()
  oBrw:SetFocus()
  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }

  oWndItems:oClient = oBrw
  oWndItems:oControl = oBrw

  DEFINE MSGBAR oMsgBar OF oWndItems 2007

  ACTIVATE WINDOW oWndItems MAXIMIZED ;
     VALID ( oWndItems := nil, .T. )
   else
      oWndItems:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function Invoices()

   local oBrw, oChild, cClrBack, cCol
   local oBar, oMsgBar, oMsgDeleted, oRs1, oRs2

   if oWndClients == nil
      Clients()
   endif

   if oWndItems == nil
      Items()
   endif

   if oWndInvoices == nil
      oRs1 = oCn:RowSet( "SELECT * FROM invoices ORDER BY code" )
      oRs2 = oCn:RowSet( "SELECT * FROM invitems ORDER BY itemcode" )

  DEFINE WINDOW oWndInvoices MDICHILD OF oWndMain TITLE "Invoices"

  @ 60, 0 XBROWSE oBrw SIZE 0,200 PIXEL OF oWndInvoices LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRs1 NOBORDER FOOTERS

  oBar  := BrwBtnBar( @oBrw, oWndInvoices )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION ViewInvoice( oBrw )

  DEFINE BUTTON OF oBar PROMPT "EasyReport" RESOURCE "report" ;
     ACTION ViewInvoiceER( oBrw )

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndInvoices:End()

  DEFINE MSGBAR oMsgBar OF oWndInvoices 2007

  BrwColors( oBrw )
  BrwRecSel( oBrw, "RECNO" )

  for each cCol in { "Amount", "Tax", "Total" }
     oBrw:oCol( cCol ):nFooterType  := AGGR_SUM
  next

  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }
  oBrw:bEdit = { | oRec | EditInvoice( oRec ) }
  oBrw:MakeTotals()
  oBrw:CreateFromCode()
  oBrw:SetFocus()

  oWndInvoices:oControl = oBrw

  @ oBar:nHeight + 200,0 XBROWSE oChild SIZE 0,-oMsgBar:nHeight PIXEL OF oWndInvoices ;
     DATASOURCE oRs2 ;
     COLUMNS "ItemCode", "ItemName", "Quantity", "Unit", "Price", ;
             "ROUND(QUANTITY*PRICE,0)", "DISCOUNT","ROUND(QUANTITY*PRICE,0)-DISCOUNT" ;
     HEADERS "ItmCode", nil, nil, nil, nil, "Amount", "Discount", "Net Amount" ;
     LINES NOBORDER FOOTERS

  BrwColors( oChild )
  // BrwRecSel( oChild, "KEY" )

  for each cCol in { "Amount", "Discount", "Net Amount" }
     WITH OBJECT oChild:oCol( cCol )
        :nFooterType   := AGGR_SUM
     END
  next
  oChild:MakeTotals()
  oChild:CreateFromCode()

  oBrw:bChange   := { || oChild:Refresh(), oChild:MakeTotals(), oChild:GoTop() }

  oWndInvoices:bResized := < ||
     local oRect    := oWndInvoices:GetCliRect()
     oBrw:nHeight   := ( oRect:nHeight - oBar:nHeight - oMsgBar:nHeight ) * 0.6
     oChild:nTop    := oBrw:nTop + oBrw:nHeight
     return nil
     >

  oWndInvoices:bPostEnd   := { || oWndInvoices := nil }

  ACTIVATE WINDOW oWndInvoices MAXIMIZED

   else
      oWndInvoices:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function EditInvoice( oRec )

   local lNew     := ( oRec:RecNo == 0 )
   local oDlg, oBrush, oFont, oBold, oLarge
   local oBrw, cCol, bInit, oBtn
   local aItems
   local oGetClient, cClient, bCliInit
   local nHt      := Int( ScreenHeight() * 0.8 )
   local nWd      := 1100
   local lSave    := .f.

   if lNew
      oRec:Date      := Date()
      oRec:TaxRate   := nTaxRate
      aItems         := { AClone( aBlankItem ) }
   else
      aItems         := IIT->( FW_DbfToArray( cItemFlds, { || IIT->INVNUM == oRec:InvNum } ) )
   endif

   DEFINE BRUSH oBrush RESOURCE "PAPER"
   DEFINE FONT oLarge NAME "VERDANA" SIZE 0,-30 BOLD
   DEFINE FONT oFont NAME  "TAHOMA"  SIZE 0,-15
   DEFINE FONT oBold NAME  "TAHOMA"  SIZE 0,-15 BOLD

   DEFINE DIALOG oDlg SIZE nWd, nHt PIXEL FONT oFont TRUEPIXEL ;
      TITLE If( lNew, "NEW ", "EDIT " ) + "INVOICE" TRANSPARENT ;
      BRUSH oBrush

//   @  20, 40 SAY "INVOICE" SIZE 260,36 PIXEL OF oDlg FONT oLarge ;
   @  20, nWd/2-100 SAY "INVOICE" SIZE 200,36 PIXEL OF oDlg FONT oLarge CENTER

   @ 020, nWd - 190 GET oRec:InvNum PICTURE "@!" SIZE 150,26 PIXEL OF oDlg ;
      VALID ! ( Empty( oRec:InvNum ) .or. INVOICES->( Duplicate( oRec:InvNum, "INVNUM", oRec:RecNo ) ) )

   @ 050, nWd - 190 GET oRec:Date   SIZE 150,26 PIXEL OF oDlg RIGHT ;
                  ACTION oRec:Date := Min( MsgDate( oRec:Date ), Date() )

   @  80-60, 40 SAY "Client:" SIZE 100,24 PIXEL OF oDlg

   @  80-60,150 GET oGetClient VAR oRec:Code SIZE 150,26 PIXEL OF oDlg ;
         ACTION ( PopupBrowse( "CLIENTS", oGetClient ), ;
                  ReadClientInfo( oRec, oDlg ) ) ;
         VALID ( ReadClientInfo( oRec, oDlg ) )

   @ 125-60, 60 SAY oRec:Client SIZE 200,24 PIXEL OF oDlg FONT oBold UPDATE
   @ 150-60, 60 SAY oRec:Address SIZE 200, 60 PIXEL OF oDlg UPDATE

   @ 180-60,310 SAY "Text :" SIZE 100,24 PIXEL OF oDlg
   @ 204-60,310 GET oRec:Details SIZE nWd-310-40,26 PIXEL OF oDlg UPDATE

   @ 240-60,040 XBROWSE oBrw SIZE -40,-150+45 PIXEL OF oDlg ;
      DATASOURCE aItems ;
      COLUMNS 3,4,5,6,7,8 ;
      HEADERS "ITEM", "DETAILS", "QTY", "UNIT","PRICE","DISCOUNT" ;
      PICTURES "@!", nil, "9999.999", nil, "999.99", "999,999,999" ;
      COLSIZES nil, 30 ;
      CELL LINES NOBORDER FASTEDIT FOOTERS

   ADD TO oBrw AT 6 HEADER "AMOUNT" DATA ROUND( oBrw:aRow[5] * oBrw:aRow[7], 0 ) ;
      PICTURE "999,999,999"

   ADD TO oBrw HEADER "NET" DATA ROUND( oBrw:aRow[5] * oBrw:aRow[7] - oBrw:aRow[ 8 ], 0 ) ;
      PICTURE "999,999,999"

   for each cCol in { "amount", "discount", "net" }
      WITH OBJECT oBrw:oCol( cCol )
         :nFooterType   := AGGR_SUM
      END
   next

   for each cCol in { "qty", "price", "discount" }
      WITH OBJECT oBrw:oCol( cCol )
         :nEditType     := EDIT_GET
         :bEditValid    := { |o| o:VarGet() >= 0 }
         :bOnChange     := { || oBrw:MakeTotals( { "amount", "net" } ), oBrw:RefreshFooters(), oDlg:Update() }
      END
   next

   for each cCol in { "details", "unit", "amount", "net" }
      oBrw:oCol( cCol ):bClrStd  := { || { CLR_BLACK, RGB( 240, 240, 240 ) } }
   next

   // AutoAppendCode
   WITH OBJECT oBrw
      :AddVar( "AAPPEND", nil )
      :bClrStd    := { || If( oBrw:aRow == oBrw:aAppend, { CLR_BLACK, CLR_YELLOW }, { CLR_BLACK, oBrw:nClrPane } ) }

  :bChange    := { || If( oBrw:nArrayAt < oBrw:nLen, CheckAppendRow( oBrw ), nil ) }

  :bPastEof   := { || If( oBrw:aAppend != nil .and. Empty( oBrw:aAppend[ 3 ] ), nil, ;
           ( AAdd( oBrw:aArrayData, oBrw:aAppend := AClone( aBlankItem ) ), ;
             oBrw:GoBottom(), oBrw:GoLeftMost(), oBrw:RefreshCurrent(), ;
             oBrw:MakeTotals(), oBrw:Refresh() ) ) }

  :bKeyDown   := { |k| If( k == VK_DELETE, ( oBrw:aAppend := nil, oBrw:Delete(), 0 ), nil ) }

   END

   WITH OBJECT oBrw:aCols[ 1 ]
      :nEditType     = EDIT_BUTTON
      :bEditBlock    = { | nRow, nCol, oCol, nKey | TableLookUp( nRow, nCol, oCol, nKey, "ITEMS" ) }
      :bOnChange     = { || oBrw:aAppend := nil, ReadItemInfo( oBrw:aRow, oBrw ), oBrw:RefreshCurrent(), ;
                            oBrw:MakeTotals(), oBrw:RefreshFooters(), oDlg:Update() }
   END

   WITH OBJECT oBrw
      :lFlatStyle    := .t.
      :nStretchCol   := 2
      :lHScroll      := .f.
      :bOnRefresh    := { || oDlg:Update() }
      //
      BrwRecSel( oBrw, "KEYNO" )
      //
      :MakeTotals()
      :CreateFromCode()
   END

   @ nHt - 139 + 45, nWd - 380 SAY "TAX @" ;
      SIZE 80,24 PIXEL OF oDlg RIGHT

   @ nHt - 140 + 45, nWd - 280 GET oRec:TaxRate PICTURE "99.99 %" ;
      SIZE 100,26 PIXEL OF oDlg RIGHT ;
      VALID ( If( oRec:TaxRate >= 0, ( oDlg:Update(), .t. ), .f. ) )

   @ nHT - 139 + 45, nWd - 170 SAY ;
      ( oRec:Tax := ROUND( oBrw:Net:nTotal * oRec:TaxRate / 100, 0 ) ) ;
      PICTURE "999,999,999" SIZE 105,24 PIXEL OF oDlg UPDATE RIGHT

   @ nHt - 105 + 45, nWd - 270 SAY "TOTAL" SIZE 80, 24 PIXEL OF oDlg RIGHT

   @ nHt - 105 + 45, nWd - 170 SAY ;
      ( oRec:Total := oBrw:Net:nTotal + oRec:Tax ) ;
      PICTURE "999,999,999" SIZE 105, 24 PIXEL OF oDlg UPDATE RIGHT

/*
   @ nHt - 60, nWd - 260 BTNBMP PROMPT "Save"  SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION ( lSave := .t., oDlg:End() )

   @ nHt - 60, nWd - 140 BTNBMP oBtn PROMPT "Cancel" SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION oDlg:End()
   oBtn:lCancel   := .t.
*/
   @ nHt - 60, 040 BTNBMP PROMPT "Save"  SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION ( lSave := .t., oDlg:End() )

   @ nHt - 60, 160 BTNBMP oBtn PROMPT "Cancel" SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION oDlg:End()
   oBtn:lCancel   := .t.



   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT (  oDlg:Box( 110-60, 40, 230-60, 300 ), ;
                  oDlg:Line( nHt - 112 + 45, nWd - 170, nHt - 112 + 45, nWd - 55 ), ;
                  oDlg:Line( nHt -  78 + 45, nWd - 170, nHt -  78 + 45, nWd - 55 ), ;
                  oDlg:Line( nHt -  75 + 45, nWd - 170, nHt -  75 + 45, nWd - 55 )  )

   if lSave
      CheckAppendRow( oBrw )
      if Empty( aItems ) .or. Empty( oRec:InvNum ) .or. Empty( oRec:Code ) .or. oRec:Total <= 0
      else

     oRec:Amount    := oBrw:Net:nTotal

     if ! Empty( oBrw:aDeleted )
        AEval( oBrw:aDeleted, { |a| a[ 9 ] := -a[ 9 ] } )
        IIT->( FW_SaveArrayToDBF( cItemFlds, oBrw:aDeleted ) )
     endif
     AEval( aItems, { |a| a[ 1 ] := oRec:InvNum } )
     AEval( aItems, { |a,i| a[ 2 ] := i } )
     IIT->( FW_SaveArrayToDBF( cItemFlds, aItems ) )
     oRec:Save()
     WITH OBJECT oRec:oBrw
        :MakeTotals()
        :RefreshFooters()
        Eval( :bChange, oRec:oBrw )
     END
  endif

   endif

   RELEASE FONT oFont, oLarge
   RELEASE BRUSH oBrush

return nil

//----------------------------------------------------------------------------//

static function CheckAppendRow( oBrw, aAppend )

   if Empty( ATail( oBrw:aArrayData )[ 3 ] )
      ASize( oBrw:aArrayData, oBrw:nLen - 1 )
      oBrw:aAppend  := nil
      oBrw:Refresh()
   endif

return nil

//----------------------------------------------------------------------------//

static function ReadClientInfo( oRec, oDlg )

   local nSaveRec := CLIENTS->( RECNO() )
   local lValid   := .f.

   if CLIENTS->( DBSEEK( oRec:Code ) )
      oRec:Client    := TRIM( CLIENTS->FIRST ) + " " + TRIM( CLIENTS->LAST )
      oRec:Address   := CLIENTS->( PickAddress() )
      lValid         := .t.
   endif
   CLIENTS->( DBGOTO( nSaveRec ) )

   if oDlg != nil
      oDlg:Update()
   endif

return lValid

//----------------------------------------------------------------------------//

static function PickAddress()

   local aRet  := {}

   if ! Empty( FIELD->ADDRESS1 ); AAdd( aRet, TRIM( FIELD->ADDRESS1 ) ); endif
   if ! Empty( FIELD->ADDRESS2 ); AAdd( aRet, TRIM( FIELD->ADDRESS2 ) ); endif
   if ! Empty( FIELD->CITY ); AAdd( aRet, TRIM( FIELD->CITY ) + " " + TRIM( FIELD->ZIPCODE ) ); endif

   if Empty( aRet )
      return ""
   endif

return FW_ArrayAsList( aRet, CRLF )

//----------------------------------------------------------------------------//

static function ReadItemInfo( aRow, oBrw )

   local nSaveRec := ITEMS->( RECNO() )
   local lValid   := .f.

   if ITEMS->( DBSEEK( aRow[ 3 ] ) )
      aRow[ 4 ]      := TRIM( ITEMS->NAME )
      if aRow[ 5 ] == 0
         aRow[ 5 ]   := 1
      endif
      aRow[ 6 ]      := ITEMS->UNIT
      aRow[ 7 ]      := ITEMS->PRICE
      lValid         := .t.
   endif
   ITEMS->( DBGOTO( nSaveRec ) )

   if oBrw != nil
      oBrw:RefreshCurrent()
      oBrw:MakeTotals()
      oBrw:oWnd:Update()
   endif

return lValid

//----------------------------------------------------------------------------//

static function ViewInvoice( oBrw )

   local oPrn, oFontTitle, oFontBold, oFontText, oPen, n
   local nVal, nPage, nItemsByPage := 10
   local aItems := InvItems->( ;
                   FW_DbfToArray( nil, ;
                   { || InvItems->INVNUM == Invoices->INVNUM } ) )

   PRINT oPrn NAME "INVOICE" PREVIEW

   DEFINE FONT oFontTitle NAME "Arial" SIZE 0, -19 BOLD OF oPrn
   DEFINE FONT oFontBold  NAME "Arial" SIZE 0, -12 BOLD OF oPrn
   DEFINE FONT oFontText  NAME "Arial" SIZE 0, -12 OF oPrn
   DEFINE PEN oPen WIDTH 11

   for nPage = 1 to ( Len( aItems ) / nItemsByPage ) + 1
      PAGE
         oPrn:CmSay( 3.1, 2.3, "Company Name", oFontTitle )

     oPrn:CmBox( 4.4, 10.9, 7.7, 20.15, oPen )
     oPrn:CmSay( 4.7, 11.5, oBrw:Client:Value, oFontBold )
/*
      oPrn:CmSay( 5.4, 11.5, "Address 1", oFontText )
      oPrn:CmSay( 6.1, 11.5, "Address 2", oFontText )
      oPrn:CmSay( 6.8, 11.5, "City", oFontText )
*/
         @ 5.4, 11.5 PRINT TO oPrn TEXT oBrw:Address:Value SIZE 7.0 CM FONT oFontText

     oPrn:CmBox( 8.15, 2.20, 8.75, 20.15, oPen )
     oPrn:CmSay( 8.16,  2.30, "C.I.F.:", oFontBold )
     oPrn:CmSay( 8.16,  6.00, "Invoice n�:", oFontBold )
     oPrn:CmSay( 8.16,  8.30, oBrw:InvNum:Value, oFontText )
     oPrn:CmSay( 8.16, 11.20, "Date:", oFontBold )
     oPrn:CmSay( 8.20, 12.45, DToC( oBrw:Date:Value ), oFontText )
     oPrn:CmSay( 8.16, 15.60, "PayDate:", oFontBold )
     oPrn:CmSay( 8.20, 17.50, DToC( oBrw:PayDate:Value ), oFontText )

     oPrn:CmBox( 8.90, 2.20, 9.50, 20.15, oPen )
     oPrn:CmSay ( 8.91, 2.30, "Observations:", oFontBold )

     oPrn:CmBox( 9.65, 2.20, 23.25, 20.15, oPen )
     oPrn:CmLine( 9.65, 5.20, 23.25, 5.20, oPen )
     oPrn:CmLine( 9.65, 12.20, 23.25, 12.20, oPen )
     oPrn:CmLine( 9.65, 13.80, 23.25, 13.80, oPen )
     oPrn:CmLine( 9.65, 16.10, 23.25, 16.10, oPen )
     oPrn:CmLine( 9.65, 17.10, 23.25, 17.10, oPen )
     oPrn:CmLine( 10.20, 2.20, 10.20, 20.15, oPen )

     oPrn:CmSay( 9.66,  2.30, "Code", oFontBold )
     oPrn:CmSay( 9.66,  5.30, "Description", oFontBold )
     oPrn:CmSay( 9.66, 12.30, "Quantity", oFontBold )
     oPrn:CmSay( 9.66, 14.00, "Price", oFontBold )
     oPrn:CmSay( 9.66, 16.15, "Disc", oFontBold )
     oPrn:CmSay( 9.66, 18.20, "Amount", oFontBold )

  // "INVNUM,SERIAL,ITEMCODE,ITEMNAME,QUANTITY,UNIT,PRICE,DISCOUNT,RECNO()"
  //     1      2       3       4        5       6     7      8
     for n = ( ( nPage - 1 ) * nItemsByPage ) + 1 to Min( Len( aItems ), nItemsByPage * nPage )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 3, aItems[ n ][ 3 ], oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 5.5, aItems[ n ][ 4 ], oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 12.8, AllTrim( Str( aItems[ n ][ 5 ] ) ), oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 14.5, AllTrim( Str( aItems[ n ][ 7 ] ) ), oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 16.5, AllTrim( Str( aItems[ n ][ 8 ] ) ), oFontText )
        nVal  := ROUND( aItems[ n ][ 5 ] * aItems[ n ][ 7 ] - aItems[ n ][ 8 ], 0 )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 18.5, AllTrim( Str( nVal ) ), oFontText )
     next

     oPrn:CmBox( 23.40, 2.20, 27.20, 20.15, oPen )
     oPrn:CmLine( 24.00, 2.20, 24.00, 20.15, oPen )
     oPrn:CmLine( 23.40, 4.95, 26.20, 4.95, oPen )
     oPrn:CmLine( 23.40, 6.45, 26.20, 6.45, oPen )
     oPrn:CmLine( 23.40, 9.35, 26.20, 9.35, oPen )
     oPrn:CmLine( 23.40, 10.95, 26.20, 10.95, oPen )
     oPrn:CmLine( 23.40, 13.80, 26.20, 13.80, oPen )
     oPrn:CmLine( 23.40, 16.65, 26.20, 16.65, oPen )
     oPrn:CmSay( 23.50,  2.40, "BASE", oFontBold )
     oPrn:CmSay( 23.50,   5.20, "%VAT", oFontBold )
     oPrn:CmSay( 23.50,   6.75, "CUOTE", oFontBold )
     oPrn:CmSay( 23.50,   9.60, "%RE", oFontBold )
     oPrn:CmSay( 23.50,  11.20, "CUOTE", oFontBold )
     oPrn:CmSay( 23.50,  14.10, "AMOUNT", oFontBold )
     oPrn:CmSay( 23.50, 16.95, "SUM BASES:", oFontBold )

     oPrn:CmSay( 23.50 + 1.5,  2.40, cValToStr( oBrw:Amount:Value ), oFontText )
     oPrn:CmSay( 23.50 + 1.5,  5.20, cValToStr( oBrw:TaxRate:Value ), oFontText )

     oPrn:CmSay( 26.44,  2.40, "TOTAL VAT:", oFontBold )
     oPrn:CmSay( 26.44,  5.50, cValToStr( oBrw:Tax:Value ), oFontText )
     oPrn:CmSay( 26.44,  7.70, "TOTAL R.E.:", oFontBold )
     oPrn:CmSay( 26.44, 13.35, "TOTAL INVOICE", oFontBold )
     oPrn:CmSay( 26.44, 17.50, cValToStr( oBrw:Total:Value ), oFontBold )
  ENDPAGE
   next

   ENDPRINT

   oFontTitle:End()
   oFontBold:End()
   oFontText:End()
   oPen:End()

return nil

//----------------------------------------------------------------------------//

static function OpenDataBases()  

   oCn = maria_Connect( "localhost", "fwh", "fivetec1_antonio", "1234" )  
     

   if oCn == nil  

      MsgStop( "Error connecting to the DataBase" )  

      return nil  

   endif  
     

return oCn

//----------------------------------------------------------------------------//

static function BrwBtnBar( oBrw, oWnd )

   local oBar

   DEFINE BUTTONBAR oBar OF oWnd 2007 SIZE 70, 60 //70

   DEFINE BUTTON OF oBar PROMPT "New" RESOURCE "add" ;
      ACTION oBrw:EditSource( .T. )

   DEFINE BUTTON OF oBar PROMPT "Edit" RESOURCE "edit" ;
      ACTION oBrw:EditSource()

   DEFINE BUTTON OF oBar PROMPT "Delete" RESOURCE "del"

/*
   DEFINE BUTTON OF oBar PROMPT "Preview" RESOURCE "report" ;
      ACTION ViewInvoice( oBrw )

   DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
      ACTION oWndInvoices:End()
*/

return oBar

//----------------------------------------------------------------------------//

static function BrwColors( oBrw )

   local cClrBack

   oBrw:nMarqueeStyle := MARQSTYLE_HIGHLROW
   oBrw:bClrStd = { || If( oBrw:KeyNo() % 2 == 0, ;
                         { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_BLACK ),;
                           RGB( 198, 255, 198 ) }, ;
                         { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_BLACK ),;
                           RGB( 232, 255, 232 ) } ) }
   oBrw:bClrSel = { || { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_WHITE ),;
                           RGB( 0x33, 0x66, 0xCC ) } }
   cClrBack = Eval( oBrw:bClrSelFocus )[ 2 ]
   oBrw:bClrSelFocus = { || { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_WHITE ),;
                              cClrBack } }
   oBrw:SetColor( CLR_BLACK, RGB( 232, 255, 232 ) )

   oBrw:lHScroll  := .f.

return nil

//----------------------------------------------------------------------------//

static function BrwRecSel( oBrw, cHead )

   WITH OBJECT oBrw
      :lFooter    := .t.
      if "REC" $ Upper( cHead )
         :bRecSelHeader    := { || "RecNo" }
         :bRecSelData      := { |o| o:BookMark }
         :bRecSelClick     := { |o| ( o:cAlias )->( OrdSetFocus( 0 ) ), ;
                                    AEval( o:aCols, { |c| c:cOrder := "" } ), ;
                                    o:Refresh() }
      else
         :bRecSelHeader    := { || "SlNo" }
         :bRecSelData      := { |o| o:KeyNo }
      endif
      :bRecSelFooter    := { |o| o:nLen }
      :nRecSelWidth     := Replicate( '9', Len( cValToChar( Eval( oBrw:bKeyCount, oBrw ) ) ) + 1 )

   END

retur nil

//----------------------------------------------------------------------------//

static function EditItems( oRec )

   local oDlg
   local lSave := .F.
   local oFont
   local oBtn
   local lAdd  := ( oRec:RecNo == 0 )

   DEFINE FONT oFont NAME "Tahoma" SIZE 0, -15

   DEFINE DIALOG oDlg SIZE 402, 158 PIXEL FONT oFont ;
      TITLE If( lAdd, "New Item", "Edit Item" )

   @ 12, 10 SAY "Code:" OF oDlg SIZE 19, 8 PIXEL FONT oFont
   @ 10, 36 GET oRec:Code  OF oDlg SIZE 55, 12 PIXEL FONT oFont PICTURE "@!" UPDATE ;
      VALID ! Empty( oRec:Code )

   @ 26, 10 SAY "Name:" OF oDlg SIZE 21, 8 PIXEL FONT oFont
   @ 24, 36 GET oRec:Name  OF oDlg SIZE 155, 12 PIXEL FONT oFont ;
      VALID !Empty( oRec:Name ) UPDATE

   @ 40, 10 SAY "Unit:" OF oDlg SIZE 18, 8 PIXEL FONT oFont
//   @ 38, 36 GET oRec:Unit OF oDlg SIZE 44, 12 PIXEL FONT oFont RIGHT ;
   @ 38,38 COMBOBOX oRec:Unit SIZE 44,12 PIXEL OF oDlg ;
      ITEMS { "Items","K.G","Metre","Litre" }

   @ 40, 10 + 111 SAY "Price:" OF oDlg SIZE 18, 8 PIXEL FONT oFont
   @ 38, 36 + 111 GET oRec:Price OF oDlg SIZE 44, 12 PIXEL PICTURE  "9999999.99" FONT oFont RIGHT ;
      VALID oRec:Price > 0 UPDATE

   @ 60, 111 BTNBMP oBtn PROMPT "Save" OF oDlg SIZE 42, 14 PIXEL FLAT ;
      WHEN oRec:Modified() ACTION (oDlg:End(), lSave := .T.)
   @ 60, 155 BTNBMP oBtn PROMPT "Cancel" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End())
   oBtn:lCancel   := .t.

   // oRec:bValid := { || !Duplicate( oRec:Code, "CODE", oRec:RecNo ) }

   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT ( oDlg:Box( 10, 10, 110, 392 ) )

   if lSave
      oRec:Save( .T. )    // Param .t. to check oRec:bValid
   endif

return nil

//----------------------------------------------------------------------------//

static function EditClients( oRec )

   local oDlg
   local lSave := .F.
   local oFont
   local oBtn
   local lAdd  := ( oRec:RecNo == 0 )

   DEFINE FONT oFont NAME "TAHOMA" SIZE 0, 15
   DEFINE DIALOG oDlg SIZE 422, 326 PIXEL ; //FROM 100, 100 TO 426,522;
      TITLE If( lAdd, "New Client", "Edit Client" ) FONT oFont

   @ 12, 10 SAY "Code:" OF oDlg SIZE 19, 8 PIXEL
   @ 10, 46 GET oRec:Code     OF oDlg SIZE 55, 12 PIXEL PICTURE "@!" UPDATE ;
      VALID ! Empty( oRec:Code )

   @ 26, 10 SAY "First:" OF oDlg SIZE 15, 8 PIXEL
   @ 24, 46 GET oRec:First    OF oDlg SIZE 105, 12 PIXEL UPDATE ;
      VALID ! Empty( oRec:First )

   @ 40, 10 SAY "Last:" OF oDlg SIZE 15, 8 PIXEL
   @ 38, 46 GET oRec:Last     OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 54, 10 SAY "Address1:" OF oDlg SIZE 31, 8 PIXEL
   @ 52, 46 GET oRec:Address1 OF oDlg SIZE 155, 12 PIXEL UPDATE

   @ 68, 10 SAY "Address2:" OF oDlg SIZE 31, 8 PIXEL FONT oFont
   @ 66, 46 GET oRec:Address2 OF oDlg SIZE 155, 12 PIXEL UPDATE

   @ 82, 10 SAY "City:" OF oDlg SIZE 13, 8 PIXEL
   @ 80, 46 GET oRec:City     OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 96, 10 SAY "Zipcode:" OF oDlg SIZE 28, 8 PIXEL
   @ 94, 46 GET oRec:Zipcode  OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 110, 10 SAY "Phone:" OF oDlg SIZE 23, 8 PIXEL
   @ 108, 46 GET oRec:Phone    OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 124, 10 SAY "Email:" OF oDlg SIZE 19, 8 PIXEL
   @ 122, 46 GET oRec:Email    OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 144, 121 BTNBMP oBtn PROMPT "Save" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End(), lSave := .T.) ;
      WHEN oRec:Modified()

   @ 144, 165 BTNBMP oBtn PROMPT "Cancel" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End())
   oBtn:lCancel   := .t.

   // oRec:bValid := { || !Duplicate( oRec:Code, "CODE", oRec:RecNo ) }

   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT ( oDlg:Box( 10, 10, 278, 412 ) )

   IF lSave
      oRec:Save( .T. )
   ENDIF

   RETURN NIL

//----------------------------------------------------------------------------//

static function Duplicate( uVal, cOrder, nThisRec )

   local nSaveRec    := RECNO()
   local cSaveOrd    := OrdSetFocus()
   local lExists     := .f.

   DEFAULT nThisRec := nSaveRec
   OrdSetFocus( cOrder )
   lExists  := DBSEEK( uVal ) .and. RECNO() != nThisRec
   if ! Empty( cSaveOrd )
      OrdSetFocus( cSaveOrd )
   endif
   DBGOTO( nSaveRec )

return lExists

//----------------------------------------------------------------------------//

static function TableLookUp( nRow, nCol, oCol, nKey, uSource, uRetCol, aCols )

   local oDlg, oBrw, uRet
   local aPoint
   local oFont, oBold
   local aCellCoor   := oCol:oBrw:aCellCoor()
   DEFAULT uRetCol   := 1

   DEFINE FONT oFont NAME "ARIAL" SIZE 0,-12
   DEFINE FONT oBold NAME "ARIAL" SIZE 0,-12 BOLD

   aPoint      := ClientToScreen( oCol:oBrw:hWnd, { aCellCoor[ 1 ], aCellCoor[ 2 ] } )

   ( uSource )->( DBSEEK( oCol:Value, .t. ), If( Eof(), DBGOBOTTOM(), nil ) )

   DEFINE DIALOG oDlg SIZE 300,300 PIXEL TRUEPIXEL ;
      STYLE WS_POPUP OF oCol:oBrw FONT oFont ;
      COLOR CLR_BLACK, 1
   oDlg:nSeeThroClr  := 1

   @ aCellCoor[ 3 ] - aCellCoor[ 1 ],0 XBROWSE oBrw SIZE 0,0 PIXEL OF oDlg ;
      DATASOURCE uSource AUTOCOLS ;
      AUTOSORT CELL LINES NOBORDER ;
      COLOR CLR_BLACK, RGB( 232, 255, 232 )

   WITH OBJECT oBrw
      :lHScroll         := .f.
      :lRecordSelector  := .f.
      :lDrawBorder      := .t.
      //
      :lIncrFilter      := .t.
      :lSeekWild        := .t.
      :oCol( uRetCol ):oDataFont := oBold

  if ValType( uSource ) == 'C'
     :cFilterFld := "DBRECORDINFO( 7 )"
  endif

  :bKeyDown   := { |nKey| If( nKey == VK_RETURN, (  uRet := oBrw:oCol( uRetCol ):Value, oDlg:End() ), nil ) }
  :bKeyChar   := { |nKey| If( nKey == VK_ESCAPE, ( oBrw:Seek( "" ), oDlg:End() ), nil ) }
  :bLDClickDatas := { || uRet := oBrw:oCol( uRetCol ):Value, oDlg:End() }

  :AutoFit()
  :CreateFromCode()
   END

   @ 00,00 SAY oBrw:oSeek PROMPT oBrw:cSeek PICTURE "@!" ;
      SIZE aCellCoor[ 4 ] - aCellCoor[ 2 ], aCellCoor[ 3 ] - aCellCoor[ 1 ] PIXEL OF oDlg COLOR CLR_HRED, CLR_YELLOW ;
      FONT oCol:DataFont

   WITH OBJECT oBrw:oSeek
      :lWantClick    := .t.
      :bLClicked     := { || oDlg:End() }
   END

   ACTIVATE DIALOG oDlg ;
      ON PAINT ( oDlg:Box( 0,0,20,100 ) ) ;
      ON INIT BrwHelpDlgInit( oBrw, aPoint ) ;
      VALID ( oBrw:Seek( "" ), .t. )

   RELEASE FONT oFont, oBold

return uRet

//----------------------------------------------------------------------------//

static function BrwHelpDlgInit( oBrw, aPoint )

   local oDlg  := oBrw:oWnd
   local dy    := oDlg:GetRect():nWidth - oDlg:GetCliRect():nWidth
   local aSize

   aSize := oBrw:BrwFitSize()
   oDlg:nWidth    := aSize[ 1 ] + dy
   oDlg:nHeight   := oBrw:nTop + aSize[ 2 ]

   oDlg:SetPos( aPoint[ 1 ], aPoint[ 2 ] )
   oDlg:Shadow()

return nil

//----------------------------------------------------------------------------//

static function ViewInvoiceER( oBrw )
   local oVRD
   local lPreview := .t.
   local cDruckerName := ""
   local nVal
   local aItems := InvItems->( ;
                   FW_DbfToArray( nil, ;
                   { || InvItems->INVNUM == Invoices->INVNUM } ) )
   *----------------------------------------------------------
   local aID_Strings := {}
   local aID         := {}
   local aStrings    := {}
   local cLogo := ""
   local cBezeichnung := ""
   local nPrintArea   := 3
   local n
   *----------------------------------------------------------

   TPreview():lListViewHide := .T.

   EASYREPORT oVRD NAME "yinvoice\invoice.vrd"  PREVIEW  lPreview TO cDruckerName PRINTDIALOG IIF( lPreview, .F., .F. ) MODAL

//----------------------------------------------------------------------------//
//header
//----------------------------------------------------------------------------//

#DEFINE ER_COMPANY  201
#DEFINE ER_ADDRESS  500
#DEFINE ER_CIF      501
#DEFINE ER_INVOICE  602
#DEFINE ER_DATE     502
#DEFINE ER_PAYDATE  603

PRINTAREA 5 OF oVRD


  PRINTAREA 1 OF oVRD ;
               ITEMIDS    { ER_COMPANY   ,ER_ADDRESS,  ER_CIF, ER_INVOICE, ER_DATE, ER_PAYDATE } ;
               ITEMVALUES { OBRW:CLIENT:VALUE, OBRW:ADDRESS:VALUE, "100", "220178992", DToC( oBrw:Date:Value ), DToC( oBrw:PayDate:Value ) }

//----------------------------------------------------------------------------//
// Data Header
//----------------------------------------------------------------------------//
PRINTAREA 2 OF oVRD

//----------------------------------------------------------------------------//
// Data
//----------------------------------------------------------------------------//
#DEFINE ER_CODE        200
#DEFINE ER_DESCRIPTION 201
#DEFINE ER_QUANTITY    202
#DEFINE ER_PRICE       203
#DEFINE ER_DISC        204
#DEFINE ER_AMOUNT      205

   for n = 1 to Len( aItems )




  PRINTAREA nPrintArea OF oVRD ;
           ITEMIDS    { ER_CODE ,;
                        ER_DESCRIPTION ,;
                        ER_QUANTITY ,;
                        ER_PRICE ,;
                        ER_DISC ,;
                        ER_AMOUNT  }   ;
           ITEMVALUES { aItems[ n, 3 ],;
                        aItems[ n, 4 ],;
                        AllTrim( Str( aItems[ n, 5 ] ) ),;
                        AllTrim( Str( aItems[ n, 7 ] ) ),;
                        AllTrim( Str( aItems[ n, 8 ] ) ),;
                        AllTrim( Str( ROUND( aItems[ n, 5 ] * aItems[ n, 7 ] - aItems[ n, 8 ], 0 ) ) )  }

   if nPrintArea = 3
      nPrintArea := 6
   else
      nPrintArea := 3
   endif


   next


   #UNDEF ER_AMOUNT


//----------------------------------------------------------------------------//
//Footer
//----------------------------------------------------------------------------//

 #DEFINE ER_BASE           310
 #DEFINE ER_VAT            311
 #DEFINE ER_TOTALVAT       312
 #DEFINE ER_TOTALINVOICE   313




 PRINTAREA 4 OF oVRD ;
           ITEMIDS    { ER_BASE ,;
                        ER_VAT ,;
                        ER_TOTALVAT ,;
                        ER_TOTALINVOICE  } ;
           ITEMVALUES { cValToStr( oBrw:Amount:Value ) ,;
                        cValToStr( oBrw:TaxRate:Value ) ,;
                        cValToStr( oBrw:Tax:Value ) ,;
                        cValToStr( oBrw:Total:Value )  }


   oVRD:End()


return nil

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: Unicode GET cannot be highlighted
Posted: Thu Nov 27, 2025 01:36 PM

Enhanced version:

yunusm.prg

#include "FiveWin.ch"
#include "easyrep.ch"

REQUEST DBFCDX

static oWndMain, oWndInvoices, oWndClients, oWndItems
static aBlankItem
static cItemFlds  := "INVNUM,SERIAL,ITEMCODE,ITEMNAME,QUANTITY,UNIT,PRICE,DISCOUNT,ID"
static nTaxRate   := 0.0
static oCn, oRsClients

//----------------------------------------------------------------------------//

function Main()

   local oBrush, oFont

   OpenDataBases()

   DEFINE BRUSH oBrush RESOURCE "background"
   DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-12

//   SetDlgGradient( { { 1, RGB( 199, 216, 237 ), RGB( 237, 242, 248 ) } } )

   DEFINE WINDOW oWndMain TITLE "Invoicing" MDI MENU BuildMenu() VSCROLL HSCROLL BRUSH oBrush
   oWndMain:SetFont( oFont )

   BuildMainBar()

   DEFINE MSGBAR PROMPT "Invoicing app" ;
      OF oWndMain 2007 KEYBOARD DATE

   ACTIVATE WINDOW oWndMain MAXIMIZED

   RELEASE BRUSH oBrush

return nil

//----------------------------------------------------------------------------//

INIT PROCEDURE inv_init

   SET DATE BRITISH
   SET CENTURY ON
   SET EPOCH TO ( YEAR( DATE() ) - 50 )

   RDDSETDEFAULT( "DBFCDX" )
   SET DELETED ON

   SetGetColorFocus()

   aBlankItem := { "", 0, "", "", 0.0, "", 0.0, 0.0, 0 }

return

//----------------------------------------------------------------------------//

static function BuildMainBar()

   local oBar

   DEFINE BUTTONBAR oBar OF oWndMain 2007 SIZE 70, 60 //70

   DEFINE BUTTON OF oBar PROMPT "Invoices" RESOURCE "code" ;
      ACTION Invoices()

   DEFINE BUTTON OF oBar PROMPT "Clients" RESOURCE "clients" ;
      ACTION Clients()

   DEFINE BUTTON OF oBar PROMPT "Items" RESOURCE "relation" ;
      ACTION Items()

   DEFINE BUTTON OF oBar PROMPT "Exit" RESOURCE "exit" ;
      ACTION oWndMain:End()

return nil

//----------------------------------------------------------------------------//

static function BuildMenu()

   local oMenu

   MENU oMenu

  MENUITEM "Tasks"
  MENU
     MENUITEM "Invoices" ACTION Invoices()
     //MENUITEM "Invoices items" ACTION ( "invitems" )->( XBrowse() )
     MENUITEM "Clients"  ACTION Clients()
     MENUITEM "Items"    ACTION Items()
     SEPARATOR
     MENUITEM "Exit" ACTION oWndMain:End()
  ENDMENU

  oMenu:AddMDI()
  oMenu:AddHelp( "Invoicing app", "(c) FiveTech Software" )

   ENDMENU

return oMenu

//----------------------------------------------------------------------------//

static function Clients()

   local oBrw, cClrBack, cAlias
   local oBar, oMsgBar, oMsgDeleted

   if oWndClients == nil
      oRsClients = oCn:RowSet( "SELECT * FROM clients2 ORDER BY code" )

  DEFINE WINDOW oWndClients MDICHILD OF oWndMain TITLE "Clients"

  @ 2, 0 XBROWSE oBrw OF oWndClients LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRsClients NOBORDER

  oBar  := BrwBtnBar( @oBrw, oWndClients )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION oBrw:Report( "Clients report",, .F.)

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndClients:End()

  cAlias = Alias()

  BrwColors( oBrw )
  // BrwRecSel( oBrw, "RECNO" )

  oBrw:bEdit  := { |oRec| EditClients( oRec ) }

  oBrw:CreateFromCode()
  oBrw:SetFocus()
  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }

  oWndClients:oClient = oBrw
  oWndClients:oControl = oBrw

  DEFINE MSGBAR oMsgBar OF oWndClients 2007

  ACTIVATE WINDOW oWndClients MAXIMIZED ;
     VALID ( oWndClients := nil, .T. )
   else
      oWndClients:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function Items()

   local oBrw, cClrBack
   local oBar, oMsgBar, oMsgDeleted, oRs

   if oWndItems == nil
      oRs = oCn:RowSet( "SELECT * FROM items ORDER BY code" )

  DEFINE WINDOW oWndItems MDICHILD OF oWndMain TITLE "Items"

  @ 2, 0 XBROWSE oBrw OF oWndItems LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRs NOBORDER

  oBar  := BrwBtnBar( @oBrw, oWndItems )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION oBrw:Report( "Items report",, .F.)

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndItems:End()
  BrwColors( oBrw )
  // BrwRecSel( oBrw, "RECNO" )

  oBrw:bEdit  := { |oRec| EditItems( oRec ) }

  oBrw:CreateFromCode()
  oBrw:SetFocus()
  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }

  oWndItems:oClient = oBrw
  oWndItems:oControl = oBrw

  DEFINE MSGBAR oMsgBar OF oWndItems 2007

  ACTIVATE WINDOW oWndItems MAXIMIZED ;
     VALID ( oWndItems := nil, .T. )
   else
      oWndItems:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function Invoices()

   local oBrw, oChild, cClrBack, cCol
   local oBar, oMsgBar, oMsgDeleted, oRs1, oRs2

   if oWndClients == nil
      Clients()
   endif

   if oWndItems == nil
      Items()
   endif

   if oWndInvoices == nil
      oRs1 = oCn:RowSet( "SELECT * FROM invoices ORDER BY code" )
      oRs2 = oCn:RowSet( "SELECT * FROM invitems ORDER BY itemcode" )

  DEFINE WINDOW oWndInvoices MDICHILD OF oWndMain TITLE "Invoices"

  @ 60, 0 XBROWSE oBrw SIZE 0,200 PIXEL OF oWndInvoices LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRs1 NOBORDER FOOTERS

  oBar  := BrwBtnBar( @oBrw, oWndInvoices )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION ViewInvoice( oBrw )

  DEFINE BUTTON OF oBar PROMPT "EasyReport" RESOURCE "report" ;
     ACTION ViewInvoiceER( oBrw )

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndInvoices:End()

  DEFINE MSGBAR oMsgBar OF oWndInvoices 2007

  BrwColors( oBrw )
  BrwRecSel( oBrw, "RECNO" )

  for each cCol in { "Amount", "Tax", "Total" }
     oBrw:oCol( cCol ):nFooterType  := AGGR_SUM
  next

  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }
  oBrw:bEdit = { | oRec | EditInvoice( oRec ) }
  oBrw:MakeTotals()
  oBrw:CreateFromCode()
  oBrw:SetFocus()

  oWndInvoices:oControl = oBrw

  @ oBar:nHeight + 200,0 XBROWSE oChild SIZE 0,-oMsgBar:nHeight PIXEL OF oWndInvoices ;
     DATASOURCE oRs2 ;
     COLUMNS "ItemCode", "ItemName", "Quantity", "Unit", "Price", ;
             "ROUND(QUANTITY*PRICE,0)", "DISCOUNT","ROUND(QUANTITY*PRICE,0)-DISCOUNT" ;
     HEADERS "ItmCode", nil, nil, nil, nil, "Amount", "Discount", "Net Amount" ;
     LINES NOBORDER FOOTERS

  BrwColors( oChild )
  // BrwRecSel( oChild, "KEY" )

  for each cCol in { "Amount", "Discount", "Net Amount" }
     WITH OBJECT oChild:oCol( cCol )
        :nFooterType   := AGGR_SUM
     END
  next
  oChild:MakeTotals()
  oChild:CreateFromCode()

  oBrw:bChange   := { || oChild:Refresh(), oChild:MakeTotals(), oChild:GoTop() }

  oWndInvoices:bResized := < ||
     local oRect    := oWndInvoices:GetCliRect()
     oBrw:nHeight   := ( oRect:nHeight - oBar:nHeight - oMsgBar:nHeight ) * 0.6
     oChild:nTop    := oBrw:nTop + oBrw:nHeight
     return nil
     >

  oWndInvoices:bPostEnd   := { || oWndInvoices := nil }

  ACTIVATE WINDOW oWndInvoices MAXIMIZED

   else
      oWndInvoices:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function EditInvoice( oRec )

   local lNew     := ( oRec:RecNo == 0 )
   local oDlg, oBrush, oFont, oBold, oLarge
   local oBrw, cCol, bInit, oBtn
   local aItems
   local oGetClient, cClient, bCliInit
   local nHt      := Int( ScreenHeight() * 0.8 )
   local nWd      := 1100
   local lSave    := .f.

   if lNew
      oRec:InvNum    := ""
      oRec:Date      := Date()
      oRec:TaxRate   := nTaxRate
      oRec:InvNum    := "     "
      aItems         := { AClone( aBlankItem ) }
   else
      aItems = FW_RowSetToArray( oCn:RowSet( "SELECT " + cItemFlds + ;
         " FROM invitems WHERE INVNUM = '" + oRec:InvNum + "' ORDER BY SERIAL" ),;
         cItemFlds )
   endif

   DEFINE BRUSH oBrush RESOURCE "PAPER"
   DEFINE FONT oLarge NAME "VERDANA" SIZE 0,-30 BOLD
   DEFINE FONT oFont NAME  "TAHOMA"  SIZE 0,-15
   DEFINE FONT oBold NAME  "TAHOMA"  SIZE 0,-15 BOLD

   DEFINE DIALOG oDlg SIZE nWd, nHt PIXEL FONT oFont TRUEPIXEL ;
      TITLE If( lNew, "NEW ", "EDIT " ) + "INVOICE" TRANSPARENT ;
      BRUSH oBrush

//   @  20, 40 SAY "INVOICE" SIZE 260,36 PIXEL OF oDlg FONT oLarge ;
   @  20, nWd/2-100 SAY "INVOICE" SIZE 200,36 PIXEL OF oDlg FONT oLarge CENTER

   @ 020, nWd - 190 GET oRec:InvNum PICTURE "@!" SIZE 150,26 PIXEL OF oDlg ;
      VALID ! Empty( oRec:InvNum )

   @ 050, nWd - 190 GET oRec:Date   SIZE 150,26 PIXEL OF oDlg RIGHT ;
                  ACTION oRec:Date := Min( MsgDate( oRec:Date ), Date() )

   @  80-60, 40 SAY "Client:" SIZE 100,24 PIXEL OF oDlg

   @  80-60,150 GET oGetClient VAR oRec:Code SIZE 150,26 PIXEL OF oDlg ;
         ACTION ( PopupBrowse( oRsClients, oGetClient ), ;
                  ReadClientInfo( oRec, oDlg ) ) ;
         VALID ( ReadClientInfo( oRec, oDlg ) )

   @ 125-60, 60 SAY oRec:Client SIZE 200,24 PIXEL OF oDlg FONT oBold UPDATE
   @ 150-60, 60 SAY oRec:Address SIZE 200, 60 PIXEL OF oDlg UPDATE

   @ 180-60,310 SAY "Text :" SIZE 100,24 PIXEL OF oDlg
   @ 204-60,310 GET oRec:Details SIZE nWd-310-40,26 PIXEL OF oDlg UPDATE

   @ 240-60,040 XBROWSE oBrw SIZE -40,-150+45 PIXEL OF oDlg ;
      DATASOURCE aItems ;
      COLUMNS 3,4,5,6,7,8 ;
      HEADERS "ITEM", "DETAILS", "QTY", "UNIT","PRICE","DISCOUNT" ;
      PICTURES "@!", nil, "9999.999", nil, "999.99", "999,999,999" ;
      COLSIZES nil, 30 ;
      CELL LINES NOBORDER FASTEDIT FOOTERS

   ADD TO oBrw AT 6 HEADER "AMOUNT" DATA ROUND( oBrw:aRow[5] * oBrw:aRow[7], 0 ) ;
      PICTURE "999,999,999"

   ADD TO oBrw HEADER "NET" DATA ROUND( oBrw:aRow[5] * oBrw:aRow[7] - oBrw:aRow[ 8 ], 0 ) ;
      PICTURE "999,999,999"

   for each cCol in { "amount", "discount", "net" }
      WITH OBJECT oBrw:oCol( cCol )
         :nFooterType   := AGGR_SUM
      END
   next

   for each cCol in { "qty", "price", "discount" }
      WITH OBJECT oBrw:oCol( cCol )
         :nEditType     := EDIT_GET
         :bEditValid    := { |o| o:VarGet() >= 0 }
         :bOnChange     := { || oBrw:MakeTotals( { "amount", "net" } ), oBrw:RefreshFooters(), oDlg:Update() }
      END
   next

   for each cCol in { "details", "unit", "amount", "net" }
      oBrw:oCol( cCol ):bClrStd  := { || { CLR_BLACK, RGB( 240, 240, 240 ) } }
   next

   // AutoAppendCode
   WITH OBJECT oBrw
      :AddVar( "AAPPEND", nil )
      :bClrStd    := { || If( oBrw:aRow == oBrw:aAppend, { CLR_BLACK, CLR_YELLOW }, { CLR_BLACK, oBrw:nClrPane } ) }

  :bChange    := { || If( oBrw:nArrayAt < oBrw:nLen, CheckAppendRow( oBrw ), nil ) }

  :bPastEof   := { || If( oBrw:aAppend != nil .and. Empty( oBrw:aAppend[ 3 ] ), nil, ;
           ( AAdd( oBrw:aArrayData, oBrw:aAppend := AClone( aBlankItem ) ), ;
             oBrw:GoBottom(), oBrw:GoLeftMost(), oBrw:RefreshCurrent(), ;
             oBrw:MakeTotals(), oBrw:Refresh() ) ) }

  :bKeyDown   := { |k| If( k == VK_DELETE, ( oBrw:aAppend := nil, oBrw:Delete(), 0 ), nil ) }

   END

   WITH OBJECT oBrw:aCols[ 1 ]
      :nEditType     = EDIT_BUTTON
      :bEditBlock    = { | nRow, nCol, oCol, nKey | TableLookUp( nRow, nCol, oCol, nKey, "ITEMS" ) }
      :bOnChange     = { || oBrw:aAppend := nil, ReadItemInfo( oBrw:aRow, oBrw ), oBrw:RefreshCurrent(), ;
                            oBrw:MakeTotals(), oBrw:RefreshFooters(), oDlg:Update() }
   END

   WITH OBJECT oBrw
      :lFlatStyle    := .t.
      :nStretchCol   := 2
      :lHScroll      := .f.
      :bOnRefresh    := { || oDlg:Update() }
      //
      BrwRecSel( oBrw, "KEYNO" )
      //
      :MakeTotals()
      :CreateFromCode()
   END

   @ nHt - 139 + 45, nWd - 380 SAY "TAX @" ;
      SIZE 80,24 PIXEL OF oDlg RIGHT

   @ nHt - 140 + 45, nWd - 280 GET oRec:TaxRate PICTURE "99.99 %" ;
      SIZE 100,26 PIXEL OF oDlg RIGHT ;
      VALID ( If( oRec:TaxRate >= 0, ( oDlg:Update(), .t. ), .f. ) )

   @ nHT - 139 + 45, nWd - 170 SAY ;
      ( oRec:Tax := ROUND( oBrw:Net:nTotal * oRec:TaxRate / 100, 0 ) ) ;
      PICTURE "999,999,999" SIZE 105,24 PIXEL OF oDlg UPDATE RIGHT

   @ nHt - 105 + 45, nWd - 270 SAY "TOTAL" SIZE 80, 24 PIXEL OF oDlg RIGHT

   @ nHt - 105 + 45, nWd - 170 SAY ;
      ( oRec:Total := oBrw:Net:nTotal + oRec:Tax ) ;
      PICTURE "999,999,999" SIZE 105, 24 PIXEL OF oDlg UPDATE RIGHT

/*
   @ nHt - 60, nWd - 260 BTNBMP PROMPT "Save"  SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION ( lSave := .t., oDlg:End() )

   @ nHt - 60, nWd - 140 BTNBMP oBtn PROMPT "Cancel" SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION oDlg:End()
   oBtn:lCancel   := .t.
*/
   @ nHt - 60, 040 BTNBMP PROMPT "Save"  SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION ( lSave := .t., oDlg:End() )

   @ nHt - 60, 160 BTNBMP oBtn PROMPT "Cancel" SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION oDlg:End()
   oBtn:lCancel   := .t.



   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT (  oDlg:Box( 110-60, 40, 230-60, 300 ), ;
                  oDlg:Line( nHt - 112 + 45, nWd - 170, nHt - 112 + 45, nWd - 55 ), ;
                  oDlg:Line( nHt -  78 + 45, nWd - 170, nHt -  78 + 45, nWd - 55 ), ;
                  oDlg:Line( nHt -  75 + 45, nWd - 170, nHt -  75 + 45, nWd - 55 )  )

   if lSave
      CheckAppendRow( oBrw )
      if Empty( aItems ) .or. Empty( oRec:InvNum ) .or. Empty( oRec:Code ) .or. oRec:Total <= 0
      else

     oRec:Amount    := oBrw:Net:nTotal

     if ! Empty( oBrw:aDeleted )
        AEval( oBrw:aDeleted, { |a| a[ 9 ] := -a[ 9 ] } )
        IIT->( FW_SaveArrayToDBF( cItemFlds, oBrw:aDeleted ) )
     endif
     AEval( aItems, { |a| a[ 1 ] := oRec:InvNum } )
     AEval( aItems, { |a,i| a[ 2 ] := i } )
     IIT->( FW_SaveArrayToDBF( cItemFlds, aItems ) )
     oRec:Save()
     WITH OBJECT oRec:oBrw
        :MakeTotals()
        :RefreshFooters()
        Eval( :bChange, oRec:oBrw )
     END
  endif

   endif

   RELEASE FONT oFont, oLarge
   RELEASE BRUSH oBrush

return nil

//----------------------------------------------------------------------------//

static function CheckAppendRow( oBrw, aAppend )

   if Empty( ATail( oBrw:aArrayData )[ 3 ] )
      ASize( oBrw:aArrayData, oBrw:nLen - 1 )
      oBrw:aAppend  := nil
      oBrw:Refresh()
   endif

return nil

//----------------------------------------------------------------------------//

static function ReadClientInfo( oRec, oDlg )

   local oRs := oCn:RowSet( "SELECT first, last, address1, address2, city, zipcode FROM clients2 WHERE code = '" + oRec:Code + "'" )
   local lValid   := .f.
   local aRet := {}

   if oRs:RecCount > 0
      oRs:GoTop()
      oRec:Client    := TRIM( oRs:FIRST ) + " " + TRIM( oRs:LAST )
      if ! Empty( oRs:ADDRESS1 ); AAdd( aRet, TRIM( oRs:ADDRESS1 ) ); endif
      if ! Empty( oRs:ADDRESS2 ); AAdd( aRet, TRIM( oRs:ADDRESS2 ) ); endif
      if ! Empty( oRs:CITY ); AAdd( aRet, TRIM( oRs:CITY ) + " " + TRIM( oRs:ZIPCODE ) ); endif
      oRec:Address   := If( Empty( aRet ), "", FW_ArrayAsList( aRet, CRLF ) )
      lValid         := .t.
   endif

   if oDlg != nil
      oDlg:Update()
   endif

return lValid

//----------------------------------------------------------------------------//

static function PickAddress()

   local aRet  := {}

   if ! Empty( FIELD->ADDRESS1 ); AAdd( aRet, TRIM( FIELD->ADDRESS1 ) ); endif
   if ! Empty( FIELD->ADDRESS2 ); AAdd( aRet, TRIM( FIELD->ADDRESS2 ) ); endif
   if ! Empty( FIELD->CITY ); AAdd( aRet, TRIM( FIELD->CITY ) + " " + TRIM( FIELD->ZIPCODE ) ); endif

   if Empty( aRet )
      return ""
   endif

return FW_ArrayAsList( aRet, CRLF )

static function ReadItemInfo( aRow, oBrw )

   local nSaveRec := ITEMS->( RECNO() )
   local lValid   := .f.

   if ITEMS->( DBSEEK( aRow[ 3 ] ) )
      aRow[ 4 ]      := TRIM( ITEMS->NAME )
      if aRow[ 5 ] == 0
         aRow[ 5 ]   := 1
      endif
      aRow[ 6 ]      := ITEMS->UNIT
      aRow[ 7 ]      := ITEMS->PRICE
      lValid         := .t.
   endif
   ITEMS->( DBGOTO( nSaveRec ) )

   if oBrw != nil
      oBrw:RefreshCurrent()
      oBrw:MakeTotals()
      oBrw:oWnd:Update()
   endif

return lValid

//----------------------------------------------------------------------------//

static function ViewInvoice( oBrw )

   local oPrn, oFontTitle, oFontBold, oFontText, oPen, n
   local nVal, nPage, nItemsByPage := 10
   local aItems := InvItems->( ;
                   FW_DbfToArray( nil, ;
                   { || InvItems->INVNUM == Invoices->INVNUM } ) )

   PRINT oPrn NAME "INVOICE" PREVIEW

   DEFINE FONT oFontTitle NAME "Arial" SIZE 0, -19 BOLD OF oPrn
   DEFINE FONT oFontBold  NAME "Arial" SIZE 0, -12 BOLD OF oPrn
   DEFINE FONT oFontText  NAME "Arial" SIZE 0, -12 OF oPrn
   DEFINE PEN oPen WIDTH 11

   for nPage = 1 to ( Len( aItems ) / nItemsByPage ) + 1
      PAGE
         oPrn:CmSay( 3.1, 2.3, "Company Name", oFontTitle )

     oPrn:CmBox( 4.4, 10.9, 7.7, 20.15, oPen )
     oPrn:CmSay( 4.7, 11.5, oBrw:Client:Value, oFontBold )
/*
      oPrn:CmSay( 5.4, 11.5, "Address 1", oFontText )
      oPrn:CmSay( 6.1, 11.5, "Address 2", oFontText )
      oPrn:CmSay( 6.8, 11.5, "City", oFontText )
*/
         @ 5.4, 11.5 PRINT TO oPrn TEXT oBrw:Address:Value SIZE 7.0 CM FONT oFontText

     oPrn:CmBox( 8.15, 2.20, 8.75, 20.15, oPen )
     oPrn:CmSay( 8.16,  2.30, "C.I.F.:", oFontBold )
     oPrn:CmSay( 8.16,  6.00, "Invoice n�:", oFontBold )
     oPrn:CmSay( 8.16,  8.30, oBrw:InvNum:Value, oFontText )
     oPrn:CmSay( 8.16, 11.20, "Date:", oFontBold )
     oPrn:CmSay( 8.20, 12.45, DToC( oBrw:Date:Value ), oFontText )
     oPrn:CmSay( 8.16, 15.60, "PayDate:", oFontBold )
     oPrn:CmSay( 8.20, 17.50, DToC( oBrw:PayDate:Value ), oFontText )

     oPrn:CmBox( 8.90, 2.20, 9.50, 20.15, oPen )
     oPrn:CmSay ( 8.91, 2.30, "Observations:", oFontBold )

     oPrn:CmBox( 9.65, 2.20, 23.25, 20.15, oPen )
     oPrn:CmLine( 9.65, 5.20, 23.25, 5.20, oPen )
     oPrn:CmLine( 9.65, 12.20, 23.25, 12.20, oPen )
     oPrn:CmLine( 9.65, 13.80, 23.25, 13.80, oPen )
     oPrn:CmLine( 9.65, 16.10, 23.25, 16.10, oPen )
     oPrn:CmLine( 9.65, 17.10, 23.25, 17.10, oPen )
     oPrn:CmLine( 10.20, 2.20, 10.20, 20.15, oPen )

     oPrn:CmSay( 9.66,  2.30, "Code", oFontBold )
     oPrn:CmSay( 9.66,  5.30, "Description", oFontBold )
     oPrn:CmSay( 9.66, 12.30, "Quantity", oFontBold )
     oPrn:CmSay( 9.66, 14.00, "Price", oFontBold )
     oPrn:CmSay( 9.66, 16.15, "Disc", oFontBold )
     oPrn:CmSay( 9.66, 18.20, "Amount", oFontBold )

  // "INVNUM,SERIAL,ITEMCODE,ITEMNAME,QUANTITY,UNIT,PRICE,DISCOUNT,RECNO()"
  //     1      2       3       4        5       6     7      8
     for n = ( ( nPage - 1 ) * nItemsByPage ) + 1 to Min( Len( aItems ), nItemsByPage * nPage )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 3, aItems[ n ][ 3 ], oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 5.5, aItems[ n ][ 4 ], oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 12.8, AllTrim( Str( aItems[ n ][ 5 ] ) ), oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 14.5, AllTrim( Str( aItems[ n ][ 7 ] ) ), oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 16.5, AllTrim( Str( aItems[ n ][ 8 ] ) ), oFontText )
        nVal  := ROUND( aItems[ n ][ 5 ] * aItems[ n ][ 7 ] - aItems[ n ][ 8 ], 0 )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 18.5, AllTrim( Str( nVal ) ), oFontText )
     next

     oPrn:CmBox( 23.40, 2.20, 27.20, 20.15, oPen )
     oPrn:CmLine( 24.00, 2.20, 24.00, 20.15, oPen )
     oPrn:CmLine( 23.40, 4.95, 26.20, 4.95, oPen )
     oPrn:CmLine( 23.40, 6.45, 26.20, 6.45, oPen )
     oPrn:CmLine( 23.40, 9.35, 26.20, 9.35, oPen )
     oPrn:CmLine( 23.40, 10.95, 26.20, 10.95, oPen )
     oPrn:CmLine( 23.40, 13.80, 26.20, 13.80, oPen )
     oPrn:CmLine( 23.40, 16.65, 26.20, 16.65, oPen )
     oPrn:CmSay( 23.50,  2.40, "BASE", oFontBold )
     oPrn:CmSay( 23.50,   5.20, "%VAT", oFontBold )
     oPrn:CmSay( 23.50,   6.75, "CUOTE", oFontBold )
     oPrn:CmSay( 23.50,   9.60, "%RE", oFontBold )
     oPrn:CmSay( 23.50,  11.20, "CUOTE", oFontBold )
     oPrn:CmSay( 23.50,  14.10, "AMOUNT", oFontBold )
     oPrn:CmSay( 23.50, 16.95, "SUM BASES:", oFontBold )

     oPrn:CmSay( 23.50 + 1.5,  2.40, cValToStr( oBrw:Amount:Value ), oFontText )
     oPrn:CmSay( 23.50 + 1.5,  5.20, cValToStr( oBrw:TaxRate:Value ), oFontText )

     oPrn:CmSay( 26.44,  2.40, "TOTAL VAT:", oFontBold )
     oPrn:CmSay( 26.44,  5.50, cValToStr( oBrw:Tax:Value ), oFontText )
     oPrn:CmSay( 26.44,  7.70, "TOTAL R.E.:", oFontBold )
     oPrn:CmSay( 26.44, 13.35, "TOTAL INVOICE", oFontBold )
     oPrn:CmSay( 26.44, 17.50, cValToStr( oBrw:Total:Value ), oFontBold )
  ENDPAGE
   next

   ENDPRINT

   oFontTitle:End()
   oFontBold:End()
   oFontText:End()
   oPen:End()

return nil

//----------------------------------------------------------------------------//

static function OpenDataBases()  

   oCn = maria_Connect( "localhost", "fwh", "fivetec1_antonio", "1234" )  
     

   if oCn == nil  

      MsgStop( "Error connecting to the DataBase" )  

      return nil  

   endif  
     

return oCn

//----------------------------------------------------------------------------//

static function BrwBtnBar( oBrw, oWnd )

   local oBar

   DEFINE BUTTONBAR oBar OF oWnd 2007 SIZE 70, 60 //70

   DEFINE BUTTON OF oBar PROMPT "New" RESOURCE "add" ;
      ACTION oBrw:EditSource( .T. )

   DEFINE BUTTON OF oBar PROMPT "Edit" RESOURCE "edit" ;
      ACTION oBrw:EditSource()

   DEFINE BUTTON OF oBar PROMPT "Delete" RESOURCE "del"

/*
   DEFINE BUTTON OF oBar PROMPT "Preview" RESOURCE "report" ;
      ACTION ViewInvoice( oBrw )

   DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
      ACTION oWndInvoices:End()
*/

return oBar

//----------------------------------------------------------------------------//

static function BrwColors( oBrw )

   local cClrBack

   oBrw:nMarqueeStyle := MARQSTYLE_HIGHLROW
   oBrw:bClrStd = { || If( oBrw:KeyNo() % 2 == 0, ;
                         { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_BLACK ),;
                           RGB( 198, 255, 198 ) }, ;
                         { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_BLACK ),;
                           RGB( 232, 255, 232 ) } ) }
   oBrw:bClrSel = { || { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_WHITE ),;
                           RGB( 0x33, 0x66, 0xCC ) } }
   cClrBack = Eval( oBrw:bClrSelFocus )[ 2 ]
   oBrw:bClrSelFocus = { || { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_WHITE ),;
                              cClrBack } }
   oBrw:SetColor( CLR_BLACK, RGB( 232, 255, 232 ) )

   oBrw:lHScroll  := .f.

return nil

//----------------------------------------------------------------------------//

static function BrwRecSel( oBrw, cHead )

   WITH OBJECT oBrw
      :lFooter    := .t.
      if "REC" $ Upper( cHead )
         :bRecSelHeader    := { || "RecNo" }
         :bRecSelData      := { |o| o:BookMark }
         :bRecSelClick     := { |o| ( o:cAlias )->( OrdSetFocus( 0 ) ), ;
                                    AEval( o:aCols, { |c| c:cOrder := "" } ), ;
                                    o:Refresh() }
      else
         :bRecSelHeader    := { || "SlNo" }
         :bRecSelData      := { |o| o:KeyNo }
      endif
      :bRecSelFooter    := { |o| o:nLen }
      :nRecSelWidth     := Replicate( '9', Len( cValToChar( Eval( oBrw:bKeyCount, oBrw ) ) ) + 1 )

   END

retur nil

//----------------------------------------------------------------------------//

static function EditItems( oRec )

   local oDlg
   local lSave := .F.
   local oFont
   local oBtn
   local lAdd  := ( oRec:RecNo == 0 )

   DEFINE FONT oFont NAME "Tahoma" SIZE 0, -15

   DEFINE DIALOG oDlg SIZE 402, 158 PIXEL FONT oFont ;
      TITLE If( lAdd, "New Item", "Edit Item" )

   @ 12, 10 SAY "Code:" OF oDlg SIZE 19, 8 PIXEL FONT oFont
   @ 10, 36 GET oRec:Code  OF oDlg SIZE 55, 12 PIXEL FONT oFont PICTURE "@!" UPDATE ;
      VALID ! Empty( oRec:Code )

   @ 26, 10 SAY "Name:" OF oDlg SIZE 21, 8 PIXEL FONT oFont
   @ 24, 36 GET oRec:Name  OF oDlg SIZE 155, 12 PIXEL FONT oFont ;
      VALID !Empty( oRec:Name ) UPDATE

   @ 40, 10 SAY "Unit:" OF oDlg SIZE 18, 8 PIXEL FONT oFont
//   @ 38, 36 GET oRec:Unit OF oDlg SIZE 44, 12 PIXEL FONT oFont RIGHT ;
   @ 38,38 COMBOBOX oRec:Unit SIZE 44,12 PIXEL OF oDlg ;
      ITEMS { "Items","K.G","Metre","Litre" }

   @ 40, 10 + 111 SAY "Price:" OF oDlg SIZE 18, 8 PIXEL FONT oFont
   @ 38, 36 + 111 GET oRec:Price OF oDlg SIZE 44, 12 PIXEL PICTURE  "9999999.99" FONT oFont RIGHT ;
      VALID oRec:Price > 0 UPDATE

   @ 60, 111 BTNBMP oBtn PROMPT "Save" OF oDlg SIZE 42, 14 PIXEL FLAT ;
      WHEN oRec:Modified() ACTION (oDlg:End(), lSave := .T.)
   @ 60, 155 BTNBMP oBtn PROMPT "Cancel" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End())
   oBtn:lCancel   := .t.

   // oRec:bValid := { || !Duplicate( oRec:Code, "CODE", oRec:RecNo ) }

   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT ( oDlg:Box( 10, 10, 110, 392 ) )

   if lSave
      oRec:Save( .T. )    // Param .t. to check oRec:bValid
   endif

return nil

//----------------------------------------------------------------------------//

static function EditClients( oRec )

   local oDlg
   local lSave := .F.
   local oFont
   local oBtn
   local lAdd  := ( oRec:RecNo == 0 )

   DEFINE FONT oFont NAME "TAHOMA" SIZE 0, 15
   DEFINE DIALOG oDlg SIZE 422, 326 PIXEL ; //FROM 100, 100 TO 426,522;
      TITLE If( lAdd, "New Client", "Edit Client" ) FONT oFont

   @ 12, 10 SAY "Code:" OF oDlg SIZE 19, 8 PIXEL
   @ 10, 46 GET oRec:Code     OF oDlg SIZE 55, 12 PIXEL PICTURE "@!" UPDATE ;
      VALID ! Empty( oRec:Code )

   @ 26, 10 SAY "First:" OF oDlg SIZE 15, 8 PIXEL
   @ 24, 46 GET oRec:First    OF oDlg SIZE 105, 12 PIXEL UPDATE ;
      VALID ! Empty( oRec:First )

   @ 40, 10 SAY "Last:" OF oDlg SIZE 15, 8 PIXEL
   @ 38, 46 GET oRec:Last     OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 54, 10 SAY "Address1:" OF oDlg SIZE 31, 8 PIXEL
   @ 52, 46 GET oRec:Address1 OF oDlg SIZE 155, 12 PIXEL UPDATE

   @ 68, 10 SAY "Address2:" OF oDlg SIZE 31, 8 PIXEL FONT oFont
   @ 66, 46 GET oRec:Address2 OF oDlg SIZE 155, 12 PIXEL UPDATE

   @ 82, 10 SAY "City:" OF oDlg SIZE 13, 8 PIXEL
   @ 80, 46 GET oRec:City     OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 96, 10 SAY "Zipcode:" OF oDlg SIZE 28, 8 PIXEL
   @ 94, 46 GET oRec:Zipcode  OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 110, 10 SAY "Phone:" OF oDlg SIZE 23, 8 PIXEL
   @ 108, 46 GET oRec:Phone    OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 124, 10 SAY "Email:" OF oDlg SIZE 19, 8 PIXEL
   @ 122, 46 GET oRec:Email    OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 144, 121 BTNBMP oBtn PROMPT "Save" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End(), lSave := .T.) ;
      WHEN oRec:Modified()

   @ 144, 165 BTNBMP oBtn PROMPT "Cancel" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End())
   oBtn:lCancel   := .t.

   // oRec:bValid := { || !Duplicate( oRec:Code, "CODE", oRec:RecNo ) }

   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT ( oDlg:Box( 10, 10, 278, 412 ) )

   IF lSave
      oRec:Save( .T. )
   ENDIF

   RETURN NIL

//----------------------------------------------------------------------------//

static function Duplicate( uVal, cOrder, nThisRec )

   local nSaveRec    := RECNO()
   local cSaveOrd    := OrdSetFocus()
   local lExists     := .f.

   DEFAULT nThisRec := nSaveRec
   OrdSetFocus( cOrder )
   lExists  := DBSEEK( uVal ) .and. RECNO() != nThisRec
   if ! Empty( cSaveOrd )
      OrdSetFocus( cSaveOrd )
   endif
   DBGOTO( nSaveRec )

return lExists

//----------------------------------------------------------------------------//

static function TableLookUp( nRow, nCol, oCol, nKey, uSource, uRetCol, aCols )

   local oDlg, oBrw, uRet
   local aPoint
   local oFont, oBold
   local aCellCoor   := oCol:oBrw:aCellCoor()
   DEFAULT uRetCol   := 1

   DEFINE FONT oFont NAME "ARIAL" SIZE 0,-12
   DEFINE FONT oBold NAME "ARIAL" SIZE 0,-12 BOLD

   aPoint      := ClientToScreen( oCol:oBrw:hWnd, { aCellCoor[ 1 ], aCellCoor[ 2 ] } )

   ( uSource )->( DBSEEK( oCol:Value, .t. ), If( Eof(), DBGOBOTTOM(), nil ) )

   DEFINE DIALOG oDlg SIZE 300,300 PIXEL TRUEPIXEL ;
      STYLE WS_POPUP OF oCol:oBrw FONT oFont ;
      COLOR CLR_BLACK, 1
   oDlg:nSeeThroClr  := 1

   @ aCellCoor[ 3 ] - aCellCoor[ 1 ],0 XBROWSE oBrw SIZE 0,0 PIXEL OF oDlg ;
      DATASOURCE uSource AUTOCOLS ;
      AUTOSORT CELL LINES NOBORDER ;
      COLOR CLR_BLACK, RGB( 232, 255, 232 )

   WITH OBJECT oBrw
      :lHScroll         := .f.
      :lRecordSelector  := .f.
      :lDrawBorder      := .t.
      //
      :lIncrFilter      := .t.
      :lSeekWild        := .t.
      :oCol( uRetCol ):oDataFont := oBold

  if ValType( uSource ) == 'C'
     :cFilterFld := "DBRECORDINFO( 7 )"
  endif

  :bKeyDown   := { |nKey| If( nKey == VK_RETURN, (  uRet := oBrw:oCol( uRetCol ):Value, oDlg:End() ), nil ) }
  :bKeyChar   := { |nKey| If( nKey == VK_ESCAPE, ( oBrw:Seek( "" ), oDlg:End() ), nil ) }
  :bLDClickDatas := { || uRet := oBrw:oCol( uRetCol ):Value, oDlg:End() }

  :AutoFit()
  :CreateFromCode()
   END

   @ 00,00 SAY oBrw:oSeek PROMPT oBrw:cSeek PICTURE "@!" ;
      SIZE aCellCoor[ 4 ] - aCellCoor[ 2 ], aCellCoor[ 3 ] - aCellCoor[ 1 ] PIXEL OF oDlg COLOR CLR_HRED, CLR_YELLOW ;
      FONT oCol:DataFont

   WITH OBJECT oBrw:oSeek
      :lWantClick    := .t.
      :bLClicked     := { || oDlg:End() }
   END

   ACTIVATE DIALOG oDlg ;
      ON PAINT ( oDlg:Box( 0,0,20,100 ) ) ;
      ON INIT BrwHelpDlgInit( oBrw, aPoint ) ;
      VALID ( oBrw:Seek( "" ), .t. )

   RELEASE FONT oFont, oBold

return uRet

//----------------------------------------------------------------------------//

static function BrwHelpDlgInit( oBrw, aPoint )

   local oDlg  := oBrw:oWnd
   local dy    := oDlg:GetRect():nWidth - oDlg:GetCliRect():nWidth
   local aSize

   aSize := oBrw:BrwFitSize()
   oDlg:nWidth    := aSize[ 1 ] + dy
   oDlg:nHeight   := oBrw:nTop + aSize[ 2 ]

   oDlg:SetPos( aPoint[ 1 ], aPoint[ 2 ] )
   oDlg:Shadow()

return nil

//----------------------------------------------------------------------------//

static function ViewInvoiceER( oBrw )
   local oVRD
   local lPreview := .t.
   local cDruckerName := ""
   local nVal
   local aItems := InvItems->( ;
                   FW_DbfToArray( nil, ;
                   { || InvItems->INVNUM == Invoices->INVNUM } ) )
   *----------------------------------------------------------
   local aID_Strings := {}
   local aID         := {}
   local aStrings    := {}
   local cLogo := ""
   local cBezeichnung := ""
   local nPrintArea   := 3
   local n
   *----------------------------------------------------------

   TPreview():lListViewHide := .T.

   EASYREPORT oVRD NAME "yinvoice\invoice.vrd"  PREVIEW  lPreview TO cDruckerName PRINTDIALOG IIF( lPreview, .F., .F. ) MODAL

//----------------------------------------------------------------------------//
//header
//----------------------------------------------------------------------------//

#DEFINE ER_COMPANY  201
#DEFINE ER_ADDRESS  500
#DEFINE ER_CIF      501
#DEFINE ER_INVOICE  602
#DEFINE ER_DATE     502
#DEFINE ER_PAYDATE  603

PRINTAREA 5 OF oVRD


  PRINTAREA 1 OF oVRD ;
               ITEMIDS    { ER_COMPANY   ,ER_ADDRESS,  ER_CIF, ER_INVOICE, ER_DATE, ER_PAYDATE } ;
               ITEMVALUES { OBRW:CLIENT:VALUE, OBRW:ADDRESS:VALUE, "100", "220178992", DToC( oBrw:Date:Value ), DToC( oBrw:PayDate:Value ) }

//----------------------------------------------------------------------------//
// Data Header
//----------------------------------------------------------------------------//
PRINTAREA 2 OF oVRD

//----------------------------------------------------------------------------//
// Data
//----------------------------------------------------------------------------//
#DEFINE ER_CODE        200
#DEFINE ER_DESCRIPTION 201
#DEFINE ER_QUANTITY    202
#DEFINE ER_PRICE       203
#DEFINE ER_DISC        204
#DEFINE ER_AMOUNT      205

   for n = 1 to Len( aItems )




  PRINTAREA nPrintArea OF oVRD ;
           ITEMIDS    { ER_CODE ,;
                        ER_DESCRIPTION ,;
                        ER_QUANTITY ,;
                        ER_PRICE ,;
                        ER_DISC ,;
                        ER_AMOUNT  }   ;
           ITEMVALUES { aItems[ n, 3 ],;
                        aItems[ n, 4 ],;
                        AllTrim( Str( aItems[ n, 5 ] ) ),;
                        AllTrim( Str( aItems[ n, 7 ] ) ),;
                        AllTrim( Str( aItems[ n, 8 ] ) ),;
                        AllTrim( Str( ROUND( aItems[ n, 5 ] * aItems[ n, 7 ] - aItems[ n, 8 ], 0 ) ) )  }

   if nPrintArea = 3
      nPrintArea := 6
   else
      nPrintArea := 3
   endif


   next


   #UNDEF ER_AMOUNT


//----------------------------------------------------------------------------//
//Footer
//----------------------------------------------------------------------------//

 #DEFINE ER_BASE           310
 #DEFINE ER_VAT            311
 #DEFINE ER_TOTALVAT       312
 #DEFINE ER_TOTALINVOICE   313




 PRINTAREA 4 OF oVRD ;
           ITEMIDS    { ER_BASE ,;
                        ER_VAT ,;
                        ER_TOTALVAT ,;
                        ER_TOTALINVOICE  } ;
           ITEMVALUES { cValToStr( oBrw:Amount:Value ) ,;
                        cValToStr( oBrw:TaxRate:Value ) ,;
                        cValToStr( oBrw:Tax:Value ) ,;
                        cValToStr( oBrw:Total:Value )  }


   oVRD:End()


return nil

//----------------------------------------------------------------------------//

function FW_RowSetToArray( oRs, cItemFlds )

   local aItems := {}

   oRs:GoTop()
   while ! oRs:Eof()
      AAdd( aItems,;
          { oRs:INVNUM, oRs:SERIAL, oRs:ITEMCODE, oRs:ITEMNAME, oRs:QUANTITY,;
            oRs:UNIT, oRs:PRICE, oRs:DISCOUNT, oRs:ID } )
      oRs:Skip()
   end
   

return aItems   

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: Unicode GET cannot be highlighted
Posted: Thu Nov 27, 2025 02:47 PM

Enhanced version: Invoices already working :wink:

yunusm.prg

#include "FiveWin.ch"
#include "easyrep.ch"

REQUEST DBFCDX

static oWndMain, oWndInvoices, oWndClients, oWndItems
static aBlankItem
static cItemFlds  := "INVNUM,SERIAL,ITEMCODE,ITEMNAME,QUANTITY,UNIT,PRICE,DISCOUNT,ID"
static nTaxRate   := 0.0
static oCn, oRsClients

//----------------------------------------------------------------------------//

function Main()

   local oBrush, oFont

   OpenDataBases()

   DEFINE BRUSH oBrush RESOURCE "background"
   DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-12

//   SetDlgGradient( { { 1, RGB( 199, 216, 237 ), RGB( 237, 242, 248 ) } } )

   DEFINE WINDOW oWndMain TITLE "Invoicing" MDI MENU BuildMenu() VSCROLL HSCROLL BRUSH oBrush
   oWndMain:SetFont( oFont )

   BuildMainBar()

   DEFINE MSGBAR PROMPT "Invoicing app" ;
      OF oWndMain 2007 KEYBOARD DATE

   ACTIVATE WINDOW oWndMain MAXIMIZED

   RELEASE BRUSH oBrush

return nil

//----------------------------------------------------------------------------//

INIT PROCEDURE inv_init

   SET DATE BRITISH
   SET CENTURY ON
   SET EPOCH TO ( YEAR( DATE() ) - 50 )

   RDDSETDEFAULT( "DBFCDX" )
   SET DELETED ON

   SetGetColorFocus()

   aBlankItem := { "", 0, "", "", 0.0, "", 0.0, 0.0, 0 }

return

//----------------------------------------------------------------------------//

static function BuildMainBar()

   local oBar

   DEFINE BUTTONBAR oBar OF oWndMain 2007 SIZE 70, 60 //70

   DEFINE BUTTON OF oBar PROMPT "Invoices" RESOURCE "code" ;
      ACTION Invoices()

   DEFINE BUTTON OF oBar PROMPT "Clients" RESOURCE "clients" ;
      ACTION Clients()

   DEFINE BUTTON OF oBar PROMPT "Items" RESOURCE "relation" ;
      ACTION Items()

   DEFINE BUTTON OF oBar PROMPT "Exit" RESOURCE "exit" ;
      ACTION oWndMain:End()

return nil

//----------------------------------------------------------------------------//

static function BuildMenu()

   local oMenu

   MENU oMenu

  MENUITEM "Tasks"
  MENU
     MENUITEM "Invoices" ACTION Invoices()
     //MENUITEM "Invoices items" ACTION ( "invitems" )->( XBrowse() )
     MENUITEM "Clients"  ACTION Clients()
     MENUITEM "Items"    ACTION Items()
     SEPARATOR
     MENUITEM "Exit" ACTION oWndMain:End()
  ENDMENU

  oMenu:AddMDI()
  oMenu:AddHelp( "Invoicing app", "(c) FiveTech Software" )

   ENDMENU

return oMenu

//----------------------------------------------------------------------------//

static function Clients()

   local oBrw, cClrBack, cAlias
   local oBar, oMsgBar, oMsgDeleted

   if oWndClients == nil
      oRsClients = oCn:RowSet( "SELECT * FROM clients2 ORDER BY code" )

  DEFINE WINDOW oWndClients MDICHILD OF oWndMain TITLE "Clients"

  @ 2, 0 XBROWSE oBrw OF oWndClients LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRsClients NOBORDER

  oBar  := BrwBtnBar( @oBrw, oWndClients )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION oBrw:Report( "Clients report",, .F.)

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndClients:End()

  cAlias = Alias()

  BrwColors( oBrw )
  // BrwRecSel( oBrw, "RECNO" )

  oBrw:bEdit  := { |oRec| EditClients( oRec ) }

  oBrw:CreateFromCode()
  oBrw:SetFocus()
  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }

  oWndClients:oClient = oBrw
  oWndClients:oControl = oBrw

  DEFINE MSGBAR oMsgBar OF oWndClients 2007

  ACTIVATE WINDOW oWndClients MAXIMIZED ;
     VALID ( oWndClients := nil, .T. )
   else
      oWndClients:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function Items()

   local oBrw, cClrBack
   local oBar, oMsgBar, oMsgDeleted, oRs

   if oWndItems == nil
      oRs = oCn:RowSet( "SELECT * FROM items ORDER BY code" )

  DEFINE WINDOW oWndItems MDICHILD OF oWndMain TITLE "Items"

  @ 2, 0 XBROWSE oBrw OF oWndItems LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRs NOBORDER

  oBar  := BrwBtnBar( @oBrw, oWndItems )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION oBrw:Report( "Items report",, .F.)

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndItems:End()
  BrwColors( oBrw )
  // BrwRecSel( oBrw, "RECNO" )

  oBrw:bEdit  := { |oRec| EditItems( oRec ) }

  oBrw:CreateFromCode()
  oBrw:SetFocus()
  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }

  oWndItems:oClient = oBrw
  oWndItems:oControl = oBrw

  DEFINE MSGBAR oMsgBar OF oWndItems 2007

  ACTIVATE WINDOW oWndItems MAXIMIZED ;
     VALID ( oWndItems := nil, .T. )
   else
      oWndItems:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function Invoices()

   local oBrw, oChild, cClrBack, cCol
   local oBar, oMsgBar, oMsgDeleted, oRs1, oRs2

   if oWndClients == nil
      Clients()
   endif

   if oWndItems == nil
      Items()
   endif

   if oWndInvoices == nil
      oRs1 = oCn:RowSet( "SELECT * FROM invoices ORDER BY code" )
      oRs2 = oCn:RowSet( "SELECT * FROM invitems ORDER BY itemcode" )

  DEFINE WINDOW oWndInvoices MDICHILD OF oWndMain TITLE "Invoices"

  @ 60, 0 XBROWSE oBrw SIZE 0,200 PIXEL OF oWndInvoices LINES AUTOSORT ;
     AUTOCOLS DATASOURCE oRs1 NOBORDER FOOTERS

  oBar  := BrwBtnBar( @oBrw, oWndInvoices )

  DEFINE BUTTON OF oBar PROMPT "Print" RESOURCE "report" ;
     ACTION ViewInvoice( oBrw )

  DEFINE BUTTON OF oBar PROMPT "EasyReport" RESOURCE "report" ;
     ACTION ViewInvoiceER( oBrw )

  DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
     ACTION oWndInvoices:End()

  DEFINE MSGBAR oMsgBar OF oWndInvoices 2007

  BrwColors( oBrw )
  BrwRecSel( oBrw, "RECNO" )

  for each cCol in { "Amount", "Tax", "Total" }
     oBrw:oCol( cCol ):nFooterType  := AGGR_SUM
  next

  oBrw:bLDblClick = { || oBrw:EditSource(,, .T.) }
  oBrw:bEdit = { | oRec | EditInvoice( oRec ) }
  oBrw:MakeTotals()
  oBrw:CreateFromCode()
  oBrw:SetFocus()

  oWndInvoices:oControl = oBrw

  @ oBar:nHeight + 200,0 XBROWSE oChild SIZE 0,-oMsgBar:nHeight PIXEL OF oWndInvoices ;
     DATASOURCE oRs2 ;
     COLUMNS "ItemCode", "ItemName", "Quantity", "Unit", "Price", ;
             "ROUND(QUANTITY*PRICE,0)", "DISCOUNT","ROUND(QUANTITY*PRICE,0)-DISCOUNT" ;
     HEADERS "ItmCode", nil, nil, nil, nil, "Amount", "Discount", "Net Amount" ;
     LINES NOBORDER FOOTERS

  BrwColors( oChild )
  // BrwRecSel( oChild, "KEY" )

  for each cCol in { "Amount", "Discount", "Net Amount" }
     WITH OBJECT oChild:oCol( cCol )
        :nFooterType   := AGGR_SUM
     END
  next
  oChild:MakeTotals()
  oChild:CreateFromCode()

  oBrw:bChange   := { || oChild:Refresh(), oChild:MakeTotals(), oChild:GoTop() }

  oWndInvoices:bResized := < ||
     local oRect    := oWndInvoices:GetCliRect()
     oBrw:nHeight   := ( oRect:nHeight - oBar:nHeight - oMsgBar:nHeight ) * 0.6
     oChild:nTop    := oBrw:nTop + oBrw:nHeight
     return nil
     >

  oWndInvoices:bPostEnd   := { || oWndInvoices := nil }

  ACTIVATE WINDOW oWndInvoices MAXIMIZED

   else
      oWndInvoices:SetFocus()
   endif

return nil

//----------------------------------------------------------------------------//

static function EditInvoice( oRec )

   local lNew     := ( oRec:RecNo == 0 )
   local oDlg, oBrush, oFont, oBold, oLarge
   local oBrw, cCol, bInit, oBtn
   local aItems
   local oGetClient, cClient, bCliInit
   local nHt      := Int( ScreenHeight() * 0.8 )
   local nWd      := 1100
   local lSave    := .f., aItem

   if lNew
      oRec:Date      := Date()
      oRec:TaxRate   := nTaxRate
      oRec:InvNum    := Space( 10 )
      oRec:Code      := Space( 10 )
      aItems         := { AClone( aBlankItem ) }
   else
      aItems = FW_RowSetToArray( oCn:RowSet( "SELECT " + cItemFlds + ;
         " FROM invitems WHERE INVNUM = '" + oRec:InvNum + "' ORDER BY SERIAL" ),;
         cItemFlds )
   endif

   DEFINE BRUSH oBrush RESOURCE "PAPER"
   DEFINE FONT oLarge NAME "VERDANA" SIZE 0,-30 BOLD
   DEFINE FONT oFont NAME  "TAHOMA"  SIZE 0,-15
   DEFINE FONT oBold NAME  "TAHOMA"  SIZE 0,-15 BOLD

   DEFINE DIALOG oDlg SIZE nWd, nHt PIXEL FONT oFont TRUEPIXEL ;
      TITLE If( lNew, "NEW ", "EDIT " ) + "INVOICE" TRANSPARENT ;
      BRUSH oBrush

//   @  20, 40 SAY "INVOICE" SIZE 260,36 PIXEL OF oDlg FONT oLarge ;
   @  20, nWd/2-100 SAY "INVOICE" SIZE 200,36 PIXEL OF oDlg FONT oLarge CENTER

   @ 020, nWd - 190 GET oRec:InvNum PICTURE "@!" SIZE 150,26 PIXEL OF oDlg ;
      VALID ! Empty( oRec:InvNum )

   @ 050, nWd - 190 GET oRec:Date   SIZE 150,26 PIXEL OF oDlg RIGHT ;
                  ACTION oRec:Date := Min( MsgDate( oRec:Date ), Date() )

   @  80-60, 40 SAY "Client:" SIZE 100,24 PIXEL OF oDlg

   @  80-60,150 GET oGetClient VAR oRec:Code SIZE 150,26 PIXEL OF oDlg ;
         ACTION ( PopupBrowse( oRsClients, oGetClient ), ;
                  ReadClientInfo( oRec, oDlg ) ) ;
         VALID ( ReadClientInfo( oRec, oDlg ) )

   @ 125-60, 60 SAY oRec:Client SIZE 200,24 PIXEL OF oDlg FONT oBold UPDATE
   @ 150-60, 60 SAY oRec:Address SIZE 200, 60 PIXEL OF oDlg UPDATE

   @ 180-60,310 SAY "Text :" SIZE 100,24 PIXEL OF oDlg
   @ 204-60,310 GET oRec:Details SIZE nWd-310-40,26 PIXEL OF oDlg UPDATE

   @ 240-60,040 XBROWSE oBrw SIZE -40,-150+45 PIXEL OF oDlg ;
      DATASOURCE aItems ;
      COLUMNS 3,4,5,6,7,8 ;
      HEADERS "ITEM", "DETAILS", "QTY", "UNIT","PRICE","DISCOUNT" ;
      PICTURES "@!", nil, "9999.999", nil, "999.99", "999,999,999" ;
      COLSIZES nil, 30 ;
      CELL LINES NOBORDER FASTEDIT FOOTERS

   ADD TO oBrw AT 6 HEADER "AMOUNT" DATA ROUND( oBrw:aRow[5] * oBrw:aRow[7], 0 ) ;
      PICTURE "999,999,999"

   ADD TO oBrw HEADER "NET" DATA ROUND( oBrw:aRow[5] * oBrw:aRow[7] - oBrw:aRow[ 8 ], 0 ) ;
      PICTURE "999,999,999"

   for each cCol in { "amount", "discount", "net" }
      WITH OBJECT oBrw:oCol( cCol )
         :nFooterType   := AGGR_SUM
      END
   next

   for each cCol in { "qty", "price", "discount" }
      WITH OBJECT oBrw:oCol( cCol )
         :nEditType     := EDIT_GET
         :bEditValid    := { |o| o:VarGet() >= 0 }
         :bOnChange     := { || oBrw:MakeTotals( { "amount", "net" } ), oBrw:RefreshFooters(), oDlg:Update() }
      END
   next

   for each cCol in { "details", "unit", "amount", "net" }
      oBrw:oCol( cCol ):bClrStd  := { || { CLR_BLACK, RGB( 240, 240, 240 ) } }
   next

   // AutoAppendCode
   WITH OBJECT oBrw
      :AddVar( "AAPPEND", nil )
      :bClrStd    := { || If( oBrw:aRow == oBrw:aAppend, { CLR_BLACK, CLR_YELLOW }, { CLR_BLACK, oBrw:nClrPane } ) }

  :bChange    := { || If( oBrw:nArrayAt < oBrw:nLen, CheckAppendRow( oBrw ), nil ) }

  :bPastEof   := { || If( oBrw:aAppend != nil .and. Empty( oBrw:aAppend[ 3 ] ), nil, ;
           ( AAdd( oBrw:aArrayData, oBrw:aAppend := AClone( aBlankItem ) ), ;
             oBrw:GoBottom(), oBrw:GoLeftMost(), oBrw:RefreshCurrent(), ;
             oBrw:MakeTotals(), oBrw:Refresh() ) ) }

  :bKeyDown   := { |k| If( k == VK_DELETE, ( oBrw:aAppend := nil, oBrw:Delete(), 0 ), nil ) }

   END

   WITH OBJECT oBrw:aCols[ 1 ]
      :nEditType     = EDIT_BUTTON
      :bEditBlock    = { | nRow, nCol, oCol, nKey | TableLookUp( nRow, nCol, oCol, nKey, "ITEMS" ) }
      :bOnChange     = { || oBrw:aAppend := nil, ReadItemInfo( oBrw:aRow, oBrw ), oBrw:RefreshCurrent(), ;
                            oBrw:MakeTotals(), oBrw:RefreshFooters(), oDlg:Update() }
   END

   WITH OBJECT oBrw
      :lFlatStyle    := .t.
      :nStretchCol   := 2
      :lHScroll      := .f.
      :bOnRefresh    := { || oDlg:Update() }
      //
      BrwRecSel( oBrw, "KEYNO" )
      //
      :MakeTotals()
      :CreateFromCode()
   END

   @ nHt - 139 + 45, nWd - 380 SAY "TAX @" ;
      SIZE 80,24 PIXEL OF oDlg RIGHT

   @ nHt - 140 + 45, nWd - 280 GET oRec:TaxRate PICTURE "99.99 %" ;
      SIZE 100,26 PIXEL OF oDlg RIGHT ;
      VALID ( If( oRec:TaxRate >= 0, ( oDlg:Update(), .t. ), .f. ) )

   @ nHT - 139 + 45, nWd - 170 SAY ;
      ( oRec:Tax := ROUND( oBrw:Net:nTotal * oRec:TaxRate / 100, 0 ) ) ;
      PICTURE "999,999,999" SIZE 105,24 PIXEL OF oDlg UPDATE RIGHT

   @ nHt - 105 + 45, nWd - 270 SAY "TOTAL" SIZE 80, 24 PIXEL OF oDlg RIGHT

   @ nHt - 105 + 45, nWd - 170 SAY ;
      ( oRec:Total := oBrw:Net:nTotal + oRec:Tax ) ;
      PICTURE "999,999,999" SIZE 105, 24 PIXEL OF oDlg UPDATE RIGHT

/*
   @ nHt - 60, nWd - 260 BTNBMP PROMPT "Save"  SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION ( lSave := .t., oDlg:End() )

   @ nHt - 60, nWd - 140 BTNBMP oBtn PROMPT "Cancel" SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION oDlg:End()
   oBtn:lCancel   := .t.
*/
   @ nHt - 60, 040 BTNBMP PROMPT "Save"  SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION ( lSave := .t., oDlg:End() )

   @ nHt - 60, 160 BTNBMP oBtn PROMPT "Cancel" SIZE 100,30 PIXEL OF oDlg FLAT ;
      ACTION oDlg:End()
   oBtn:lCancel   := .t.



   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT (  oDlg:Box( 110-60, 40, 230-60, 300 ), ;
                  oDlg:Line( nHt - 112 + 45, nWd - 170, nHt - 112 + 45, nWd - 55 ), ;
                  oDlg:Line( nHt -  78 + 45, nWd - 170, nHt -  78 + 45, nWd - 55 ), ;
                  oDlg:Line( nHt -  75 + 45, nWd - 170, nHt -  75 + 45, nWd - 55 )  )

   if lSave
      CheckAppendRow( oBrw )
      if Empty( aItems ) .or. Empty( oRec:InvNum ) .or. Empty( oRec:Code ) .or. oRec:Total <= 0
      else

     oRec:Amount    := oBrw:Net:nTotal

     if ! Empty( oBrw:aDeleted )
        for each aItem in oBrw:aDeleted
           oCn:Execute( "DELETE FROM invitems WHERE id = " + Str( ABS( aItem[9] ) ) )
        next
     endif
     AEval( aItems, { |a| a[ 1 ] := oRec:InvNum } )
     AEval( aItems, { |a,i| a[ 2 ] := i } )
     for each aItem in aItems
        oCn:Execute( "INSERT INTO invitems (invnum, serial, itemcode, itemname, quantity, unit, price, discount) VALUES ('" + aItem[1] + "', " + Str(aItem[2]) + ", '" + Str( aItem[3] ) + "', '" + aItem[4] + "', " + Str(aItem[5]) + ", '" + aItem[6] + "', " + Str(aItem[7]) + ", " + Str(aItem[8]) + ") ON DUPLICATE KEY UPDATE itemname = VALUES(itemname), quantity = VALUES(quantity), unit = VALUES(unit), price = VALUES(price), discount = VALUES(discount)" )
     next
     oRec:Save()
     WITH OBJECT oRec:oBrw
        :MakeTotals()
        :RefreshFooters()
        Eval( :bChange, oRec:oBrw )
     END
  endif

   endif

   RELEASE FONT oFont, oLarge
   RELEASE BRUSH oBrush

return nil

//----------------------------------------------------------------------------//

static function CheckAppendRow( oBrw, aAppend )

   if Empty( ATail( oBrw:aArrayData )[ 3 ] )
      ASize( oBrw:aArrayData, oBrw:nLen - 1 )
      oBrw:aAppend  := nil
      oBrw:Refresh()
   endif

return nil

//----------------------------------------------------------------------------//

static function ReadClientInfo( oRec, oDlg )

   local oRs := oCn:RowSet( "SELECT first, last, address1, address2, city, zipcode FROM clients2 WHERE code = '" + oRec:Code + "'" )
   local lValid   := .f.
   local aRet := {}

   if oRs:RecCount > 0
      oRs:GoTop()
      oRec:Client    := TRIM( oRs:FIRST ) + " " + TRIM( oRs:LAST )
      if ! Empty( oRs:ADDRESS1 ); AAdd( aRet, TRIM( oRs:ADDRESS1 ) ); endif
      if ! Empty( oRs:ADDRESS2 ); AAdd( aRet, TRIM( oRs:ADDRESS2 ) ); endif
      if ! Empty( oRs:CITY ); AAdd( aRet, TRIM( oRs:CITY ) + " " + TRIM( oRs:ZIPCODE ) ); endif
      oRec:Address   := If( Empty( aRet ), "", FW_ArrayAsList( aRet, CRLF ) )
      lValid         := .t.
   endif

   if oDlg != nil
      oDlg:Update()
   endif

return lValid

//----------------------------------------------------------------------------//

static function PickAddress()

   local aRet  := {}

   if ! Empty( FIELD->ADDRESS1 ); AAdd( aRet, TRIM( FIELD->ADDRESS1 ) ); endif
   if ! Empty( FIELD->ADDRESS2 ); AAdd( aRet, TRIM( FIELD->ADDRESS2 ) ); endif
   if ! Empty( FIELD->CITY ); AAdd( aRet, TRIM( FIELD->CITY ) + " " + TRIM( FIELD->ZIPCODE ) ); endif

   if Empty( aRet )
      return ""
   endif

return FW_ArrayAsList( aRet, CRLF )

static function ReadItemInfo( aRow, oBrw )

   local oRs := oCn:RowSet( "SELECT name, unit, price FROM items WHERE code = '" + AllTrim( Str( aRow[ 3 ] ) ) + "'" )
   local lValid   := .f.

   if oRs:RecCount > 0
      oRs:GoTop()
      aRow[ 4 ]      := TRIM( oRs:NAME )
      if aRow[ 5 ] == 0
         aRow[ 5 ]   := 1
      endif
      aRow[ 6 ]      := oRs:UNIT
      aRow[ 7 ]      := oRs:PRICE
      lValid         := .t.
   endif

   if oBrw != nil
      oBrw:RefreshCurrent()
      oBrw:MakeTotals()
      oBrw:oWnd:Update()
   endif

return lValid

//----------------------------------------------------------------------------//

static function ViewInvoice( oBrw )

   local oPrn, oFontTitle, oFontBold, oFontText, oPen, n
   local nVal, nPage, nItemsByPage := 10
   local aItems := FW_RowSetToArray( oCn:RowSet( "SELECT " + cItemFlds + ;
      " FROM invitems WHERE INVNUM = '" + ;
      oBrw:InvNum:Value + "' ORDER BY SERIAL" ), cItemFlds )

   PRINT oPrn NAME "INVOICE" PREVIEW

   DEFINE FONT oFontTitle NAME "Arial" SIZE 0, -19 BOLD OF oPrn
   DEFINE FONT oFontBold  NAME "Arial" SIZE 0, -12 BOLD OF oPrn
   DEFINE FONT oFontText  NAME "Arial" SIZE 0, -12 OF oPrn
   DEFINE PEN oPen WIDTH 2

   for nPage = 1 to ( Len( aItems ) / nItemsByPage ) + 1
      PAGE
         oPrn:CmSay( 3.1, 2.3, "Company Name", oFontTitle )

     oPrn:CmBox( 4.4, 10.9, 7.7, 20.15, oPen )
     oPrn:CmSay( 4.7, 11.5, oBrw:Client:Value, oFontBold )
/*
      oPrn:CmSay( 5.4, 11.5, "Address 1", oFontText )
      oPrn:CmSay( 6.1, 11.5, "Address 2", oFontText )
      oPrn:CmSay( 6.8, 11.5, "City", oFontText )
*/
         @ 5.4, 11.5 PRINT TO oPrn TEXT oBrw:Address:Value SIZE 7.0 CM FONT oFontText

     oPrn:CmBox( 8.15, 2.20, 8.75, 20.15, oPen )
     oPrn:CmSay( 8.16,  2.30, "C.I.F.:", oFontBold )
     oPrn:CmSay( 8.16,  6.00, "Invoice n�:", oFontBold )
     oPrn:CmSay( 8.16,  8.30, oBrw:InvNum:Value, oFontText )
     oPrn:CmSay( 8.16, 11.20, "Date:", oFontBold )
     oPrn:CmSay( 8.20, 12.45, DToC( oBrw:Date:Value ), oFontText )
     oPrn:CmSay( 8.16, 15.60, "PayDate:", oFontBold )
     oPrn:CmSay( 8.20, 17.50, DToC( oBrw:PayDate:Value ), oFontText )

     oPrn:CmBox( 8.90, 2.20, 9.50, 20.15, oPen )
     oPrn:CmSay ( 8.91, 2.30, "Observations:", oFontBold )

     oPrn:CmBox( 9.65, 2.20, 23.25, 20.15, oPen )
     oPrn:CmLine( 9.65, 5.20, 23.25, 5.20, oPen )
     oPrn:CmLine( 9.65, 12.20, 23.25, 12.20, oPen )
     oPrn:CmLine( 9.65, 13.80, 23.25, 13.80, oPen )
     oPrn:CmLine( 9.65, 16.10, 23.25, 16.10, oPen )
     oPrn:CmLine( 9.65, 17.10, 23.25, 17.10, oPen )
     oPrn:CmLine( 10.20, 2.20, 10.20, 20.15, oPen )

     oPrn:CmSay( 9.66,  2.30, "Code", oFontBold )
     oPrn:CmSay( 9.66,  5.30, "Description", oFontBold )
     oPrn:CmSay( 9.66, 12.30, "Quantity", oFontBold )
     oPrn:CmSay( 9.66, 14.00, "Price", oFontBold )
     oPrn:CmSay( 9.66, 16.15, "Disc", oFontBold )
     oPrn:CmSay( 9.66, 18.20, "Amount", oFontBold )

  // "INVNUM,SERIAL,ITEMCODE,ITEMNAME,QUANTITY,UNIT,PRICE,DISCOUNT,RECNO()"
  //     1      2       3       4        5       6     7      8
     for n = ( ( nPage - 1 ) * nItemsByPage ) + 1 to Min( Len( aItems ), nItemsByPage * nPage )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 3, aItems[ n ][ 3 ], oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 5.5, aItems[ n ][ 4 ], oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 12.8, AllTrim( Str( aItems[ n ][ 5 ] ) ), oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 14.5, AllTrim( Str( aItems[ n ][ 7 ] ) ), oFontText )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 16.5, AllTrim( Str( aItems[ n ][ 8 ] ) ), oFontText )
        nVal  := ROUND( aItems[ n ][ 5 ] * aItems[ n ][ 7 ] - aItems[ n ][ 8 ], 0 )
        oPrn:CmSay( 9.66 + n - ( ( nPage - 1 ) * nItemsByPage ), 18.5, AllTrim( Str( nVal ) ), oFontText )
     next

     oPrn:CmBox( 23.40, 2.20, 27.20, 20.15, oPen )
     oPrn:CmLine( 24.00, 2.20, 24.00, 20.15, oPen )
     oPrn:CmLine( 23.40, 4.95, 26.20, 4.95, oPen )
     oPrn:CmLine( 23.40, 6.45, 26.20, 6.45, oPen )
     oPrn:CmLine( 23.40, 9.35, 26.20, 9.35, oPen )
     oPrn:CmLine( 23.40, 10.95, 26.20, 10.95, oPen )
     oPrn:CmLine( 23.40, 13.80, 26.20, 13.80, oPen )
     oPrn:CmLine( 23.40, 16.65, 26.20, 16.65, oPen )
     oPrn:CmSay( 23.50,  2.40, "BASE", oFontBold )
     oPrn:CmSay( 23.50,   5.20, "%VAT", oFontBold )
     oPrn:CmSay( 23.50,   6.75, "CUOTE", oFontBold )
     oPrn:CmSay( 23.50,   9.60, "%RE", oFontBold )
     oPrn:CmSay( 23.50,  11.20, "CUOTE", oFontBold )
     oPrn:CmSay( 23.50,  14.10, "AMOUNT", oFontBold )
     oPrn:CmSay( 23.50, 16.95, "SUM BASES:", oFontBold )

     oPrn:CmSay( 23.50 + 1.5,  2.40, cValToStr( oBrw:Amount:Value ), oFontText )
     oPrn:CmSay( 23.50 + 1.5,  5.20, cValToStr( oBrw:TaxRate:Value ), oFontText )

     oPrn:CmSay( 26.44,  2.40, "TOTAL VAT:", oFontBold )
     oPrn:CmSay( 26.44,  5.50, cValToStr( oBrw:Tax:Value ), oFontText )
     oPrn:CmSay( 26.44,  7.70, "TOTAL R.E.:", oFontBold )
     oPrn:CmSay( 26.44, 13.35, "TOTAL INVOICE", oFontBold )
     oPrn:CmSay( 26.44, 17.50, cValToStr( oBrw:Total:Value ), oFontBold )
  ENDPAGE
   next

   ENDPRINT

   oFontTitle:End()
   oFontBold:End()
   oFontText:End()
   oPen:End()

return nil

//----------------------------------------------------------------------------//

static function OpenDataBases()  

   oCn = maria_Connect( "localhost", "fwh", "fivetec1_antonio", "1234" )  
     

   if oCn == nil  

      MsgStop( "Error connecting to the DataBase" )  

      return nil  

   endif  
     

return oCn

//----------------------------------------------------------------------------//

static function BrwBtnBar( oBrw, oWnd )

   local oBar

   DEFINE BUTTONBAR oBar OF oWnd 2007 SIZE 70, 60 //70

   DEFINE BUTTON OF oBar PROMPT "New" RESOURCE "add" ;
      ACTION oBrw:EditSource( .T. )

   DEFINE BUTTON OF oBar PROMPT "Edit" RESOURCE "edit" ;
      ACTION oBrw:EditSource()

   DEFINE BUTTON OF oBar PROMPT "Delete" RESOURCE "del"

/*
   DEFINE BUTTON OF oBar PROMPT "Preview" RESOURCE "report" ;
      ACTION ViewInvoice( oBrw )

   DEFINE BUTTON OF oBar PROMPT "Close" RESOURCE "exit" ;
      ACTION oWndInvoices:End()
*/

return oBar

//----------------------------------------------------------------------------//

static function BrwColors( oBrw )

   local cClrBack

   oBrw:nMarqueeStyle := MARQSTYLE_HIGHLROW
   oBrw:bClrStd = { || If( oBrw:KeyNo() % 2 == 0, ;
                         { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_BLACK ),;
                           RGB( 198, 255, 198 ) }, ;
                         { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_BLACK ),;
                           RGB( 232, 255, 232 ) } ) }
   oBrw:bClrSel = { || { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_WHITE ),;
                           RGB( 0x33, 0x66, 0xCC ) } }
   cClrBack = Eval( oBrw:bClrSelFocus )[ 2 ]
   oBrw:bClrSelFocus = { || { If( ( oBrw:cAlias )->( Deleted() ), CLR_HRED, CLR_WHITE ),;
                              cClrBack } }
   oBrw:SetColor( CLR_BLACK, RGB( 232, 255, 232 ) )

   oBrw:lHScroll  := .f.

return nil

//----------------------------------------------------------------------------//

static function BrwRecSel( oBrw, cHead )

   WITH OBJECT oBrw
      :lFooter    := .t.
      if "REC" $ Upper( cHead )
         :bRecSelHeader    := { || "RecNo" }
         :bRecSelData      := { |o| o:BookMark }
         :bRecSelClick     := { |o| ( o:cAlias )->( OrdSetFocus( 0 ) ), ;
                                    AEval( o:aCols, { |c| c:cOrder := "" } ), ;
                                    o:Refresh() }
      else
         :bRecSelHeader    := { || "SlNo" }
         :bRecSelData      := { |o| o:KeyNo }
      endif
      :bRecSelFooter    := { |o| o:nLen }
      :nRecSelWidth     := Replicate( '9', Len( cValToChar( Eval( oBrw:bKeyCount, oBrw ) ) ) + 1 )

   END

retur nil

//----------------------------------------------------------------------------//

static function EditItems( oRec )

   local oDlg
   local lSave := .F.
   local oFont
   local oBtn
   local lAdd  := ( oRec:RecNo == 0 )

   DEFINE FONT oFont NAME "Tahoma" SIZE 0, -15

   DEFINE DIALOG oDlg SIZE 402, 158 PIXEL FONT oFont ;
      TITLE If( lAdd, "New Item", "Edit Item" )

   @ 12, 10 SAY "Code:" OF oDlg SIZE 19, 8 PIXEL FONT oFont
   @ 10, 36 GET oRec:Code  OF oDlg SIZE 55, 12 PIXEL FONT oFont PICTURE "@!" UPDATE ;
      VALID ! Empty( oRec:Code )

   @ 26, 10 SAY "Name:" OF oDlg SIZE 21, 8 PIXEL FONT oFont
   @ 24, 36 GET oRec:Name  OF oDlg SIZE 155, 12 PIXEL FONT oFont ;
      VALID !Empty( oRec:Name ) UPDATE

   @ 40, 10 SAY "Unit:" OF oDlg SIZE 18, 8 PIXEL FONT oFont
//   @ 38, 36 GET oRec:Unit OF oDlg SIZE 44, 12 PIXEL FONT oFont RIGHT ;
   @ 38,38 COMBOBOX oRec:Unit SIZE 44,12 PIXEL OF oDlg ;
      ITEMS { "Items","K.G","Metre","Litre" }

   @ 40, 10 + 111 SAY "Price:" OF oDlg SIZE 18, 8 PIXEL FONT oFont
   @ 38, 36 + 111 GET oRec:Price OF oDlg SIZE 44, 12 PIXEL PICTURE  "9999999.99" FONT oFont RIGHT ;
      VALID oRec:Price > 0 UPDATE

   @ 60, 111 BTNBMP oBtn PROMPT "Save" OF oDlg SIZE 42, 14 PIXEL FLAT ;
      WHEN oRec:Modified() ACTION (oDlg:End(), lSave := .T.)
   @ 60, 155 BTNBMP oBtn PROMPT "Cancel" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End())
   oBtn:lCancel   := .t.

   // oRec:bValid := { || !Duplicate( oRec:Code, "CODE", oRec:RecNo ) }

   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT ( oDlg:Box( 10, 10, 110, 392 ) )

   if lSave
      oRec:Save( .T. )    // Param .t. to check oRec:bValid
   endif

return nil

//----------------------------------------------------------------------------//

static function EditClients( oRec )

   local oDlg
   local lSave := .F.
   local oFont
   local oBtn
   local lAdd  := ( oRec:RecNo == 0 )

   DEFINE FONT oFont NAME "TAHOMA" SIZE 0, 15
   DEFINE DIALOG oDlg SIZE 422, 326 PIXEL ; //FROM 100, 100 TO 426,522;
      TITLE If( lAdd, "New Client", "Edit Client" ) FONT oFont

   @ 12, 10 SAY "Code:" OF oDlg SIZE 19, 8 PIXEL
   @ 10, 46 GET oRec:Code     OF oDlg SIZE 55, 12 PIXEL PICTURE "@!" UPDATE ;
      VALID ! Empty( oRec:Code )

   @ 26, 10 SAY "First:" OF oDlg SIZE 15, 8 PIXEL
   @ 24, 46 GET oRec:First    OF oDlg SIZE 105, 12 PIXEL UPDATE ;
      VALID ! Empty( oRec:First )

   @ 40, 10 SAY "Last:" OF oDlg SIZE 15, 8 PIXEL
   @ 38, 46 GET oRec:Last     OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 54, 10 SAY "Address1:" OF oDlg SIZE 31, 8 PIXEL
   @ 52, 46 GET oRec:Address1 OF oDlg SIZE 155, 12 PIXEL UPDATE

   @ 68, 10 SAY "Address2:" OF oDlg SIZE 31, 8 PIXEL FONT oFont
   @ 66, 46 GET oRec:Address2 OF oDlg SIZE 155, 12 PIXEL UPDATE

   @ 82, 10 SAY "City:" OF oDlg SIZE 13, 8 PIXEL
   @ 80, 46 GET oRec:City     OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 96, 10 SAY "Zipcode:" OF oDlg SIZE 28, 8 PIXEL
   @ 94, 46 GET oRec:Zipcode  OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 110, 10 SAY "Phone:" OF oDlg SIZE 23, 8 PIXEL
   @ 108, 46 GET oRec:Phone    OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 124, 10 SAY "Email:" OF oDlg SIZE 19, 8 PIXEL
   @ 122, 46 GET oRec:Email    OF oDlg SIZE 105, 12 PIXEL UPDATE

   @ 144, 121 BTNBMP oBtn PROMPT "Save" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End(), lSave := .T.) ;
      WHEN oRec:Modified()

   @ 144, 165 BTNBMP oBtn PROMPT "Cancel" OF oDlg SIZE 42, 14 PIXEL FLAT ACTION (oDlg:End())
   oBtn:lCancel   := .t.

   // oRec:bValid := { || !Duplicate( oRec:Code, "CODE", oRec:RecNo ) }

   ACTIVATE DIALOG oDlg CENTERED ;
      ON PAINT ( oDlg:Box( 10, 10, 278, 412 ) )

   IF lSave
      oRec:Save( .T. )
   ENDIF

   RETURN NIL

//----------------------------------------------------------------------------//

static function Duplicate( uVal, cOrder, nThisRec )

   local nSaveRec    := RECNO()
   local cSaveOrd    := OrdSetFocus()
   local lExists     := .f.

   DEFAULT nThisRec := nSaveRec
   OrdSetFocus( cOrder )
   lExists  := DBSEEK( uVal ) .and. RECNO() != nThisRec
   if ! Empty( cSaveOrd )
      OrdSetFocus( cSaveOrd )
   endif
   DBGOTO( nSaveRec )

return lExists

//----------------------------------------------------------------------------//

static function TableLookUp( nRow, nCol, oCol, nKey, uSource, uRetCol, aCols )

   local oDlg, oBrw, uRet
   local aPoint
   local oFont, oBold
   local aCellCoor   := oCol:oBrw:aCellCoor()
   local oRs
   DEFAULT uRetCol   := 1

   DEFINE FONT oFont NAME "ARIAL" SIZE 0,-12
   DEFINE FONT oBold NAME "ARIAL" SIZE 0,-12 BOLD

   aPoint      := ClientToScreen( oCol:oBrw:hWnd, { aCellCoor[ 1 ], aCellCoor[ 2 ] } )

   oRs = oCn:RowSet( "SELECT * FROM " + Lower(uSource) + " ORDER BY code" )

   DEFINE DIALOG oDlg SIZE 300,300 PIXEL TRUEPIXEL ;
      STYLE WS_POPUP OF oCol:oBrw FONT oFont ;
      COLOR CLR_BLACK, 1
   oDlg:nSeeThroClr  := 1

   @ aCellCoor[ 3 ] - aCellCoor[ 1 ],0 XBROWSE oBrw SIZE 0,0 PIXEL OF oDlg ;
      DATASOURCE oRs AUTOCOLS ;
      AUTOSORT CELL LINES NOBORDER ;
      COLOR CLR_BLACK, RGB( 232, 255, 232 )

   WITH OBJECT oBrw
      :lHScroll         := .f.
      :lRecordSelector  := .f.
      :lDrawBorder      := .t.
      //
      :lIncrFilter      := .t.
      :lSeekWild        := .t.
      :oCol( uRetCol ):oDataFont := oBold

  :bKeyDown   := { |nKey| If( nKey == VK_RETURN, (  uRet := oBrw:oCol( uRetCol ):Value, oDlg:End() ), nil ) }
  :bKeyChar   := { |nKey| If( nKey == VK_ESCAPE, ( oBrw:Seek( "" ), oDlg:End() ), nil ) }
  :bLDClickDatas := { || uRet := oBrw:oCol( uRetCol ):Value, oDlg:End() }

  :AutoFit()
  :CreateFromCode()
  :Seek( oCol:Value )
   END

   @ 00,00 SAY oBrw:oSeek PROMPT oBrw:cSeek PICTURE "@!" ;
      SIZE aCellCoor[ 4 ] - aCellCoor[ 2 ], aCellCoor[ 3 ] - aCellCoor[ 1 ] PIXEL OF oDlg COLOR CLR_HRED, CLR_YELLOW ;
      FONT oCol:DataFont

   WITH OBJECT oBrw:oSeek
      :lWantClick    := .t.
      :bLClicked     := { || oDlg:End() }
   END

   ACTIVATE DIALOG oDlg ;
      ON PAINT ( oDlg:Box( 0,0,20,100 ) ) ;
      ON INIT BrwHelpDlgInit( oBrw, aPoint ) ;
      VALID ( oBrw:Seek( "" ), .t. )

   RELEASE FONT oFont, oBold

return uRet

//----------------------------------------------------------------------------//

static function BrwHelpDlgInit( oBrw, aPoint )

   local oDlg  := oBrw:oWnd
   local dy    := oDlg:GetRect():nWidth - oDlg:GetCliRect():nWidth
   local aSize

   aSize := oBrw:BrwFitSize()
   oDlg:nWidth    := aSize[ 1 ] + dy
   oDlg:nHeight   := oBrw:nTop + aSize[ 2 ]

   oDlg:SetPos( aPoint[ 1 ], aPoint[ 2 ] )
   oDlg:Shadow()

return nil

//----------------------------------------------------------------------------//

static function ViewInvoiceER( oBrw )
   local oVRD
   local lPreview := .t.
   local cDruckerName := ""
   local nVal
   local aItems := FW_RowSetToArray( oCn:RowSet( "SELECT " + cItemFlds + " FROM invitems WHERE INVNUM = '" + oBrw:InvNum:Value + "' ORDER BY SERIAL" ), cItemFlds )
   *----------------------------------------------------------
   local aID_Strings := {}
   local aID         := {}
   local aStrings    := {}
   local cLogo := ""
   local cBezeichnung := ""
   local nPrintArea   := 3
   local n
   *----------------------------------------------------------

   TPreview():lListViewHide := .T.

   EASYREPORT oVRD NAME "yinvoice\invoice.vrd"  PREVIEW  lPreview TO cDruckerName PRINTDIALOG IIF( lPreview, .F., .F. ) MODAL

//----------------------------------------------------------------------------//
//header
//----------------------------------------------------------------------------//

#DEFINE ER_COMPANY  201
#DEFINE ER_ADDRESS  500
#DEFINE ER_CIF      501
#DEFINE ER_INVOICE  602
#DEFINE ER_DATE     502
#DEFINE ER_PAYDATE  603

PRINTAREA 5 OF oVRD


  PRINTAREA 1 OF oVRD ;
               ITEMIDS    { ER_COMPANY   ,ER_ADDRESS,  ER_CIF, ER_INVOICE, ER_DATE, ER_PAYDATE } ;
               ITEMVALUES { OBRW:CLIENT:VALUE, OBRW:ADDRESS:VALUE, "100", "220178992", DToC( oBrw:Date:Value ), DToC( oBrw:PayDate:Value ) }

//----------------------------------------------------------------------------//
// Data Header
//----------------------------------------------------------------------------//
PRINTAREA 2 OF oVRD

//----------------------------------------------------------------------------//
// Data
//----------------------------------------------------------------------------//
#DEFINE ER_CODE        200
#DEFINE ER_DESCRIPTION 201
#DEFINE ER_QUANTITY    202
#DEFINE ER_PRICE       203
#DEFINE ER_DISC        204
#DEFINE ER_AMOUNT      205

   for n = 1 to Len( aItems )




  PRINTAREA nPrintArea OF oVRD ;
           ITEMIDS    { ER_CODE ,;
                        ER_DESCRIPTION ,;
                        ER_QUANTITY ,;
                        ER_PRICE ,;
                        ER_DISC ,;
                        ER_AMOUNT  }   ;
           ITEMVALUES { aItems[ n, 3 ],;
                        aItems[ n, 4 ],;
                        AllTrim( Str( aItems[ n, 5 ] ) ),;
                        AllTrim( Str( aItems[ n, 7 ] ) ),;
                        AllTrim( Str( aItems[ n, 8 ] ) ),;
                        AllTrim( Str( ROUND( aItems[ n, 5 ] * aItems[ n, 7 ] - aItems[ n, 8 ], 0 ) ) )  }

   if nPrintArea = 3
      nPrintArea := 6
   else
      nPrintArea := 3
   endif


   next


   #UNDEF ER_AMOUNT


//----------------------------------------------------------------------------//
//Footer
//----------------------------------------------------------------------------//

 #DEFINE ER_BASE           310
 #DEFINE ER_VAT            311
 #DEFINE ER_TOTALVAT       312
 #DEFINE ER_TOTALINVOICE   313




 PRINTAREA 4 OF oVRD ;
           ITEMIDS    { ER_BASE ,;
                        ER_VAT ,;
                        ER_TOTALVAT ,;
                        ER_TOTALINVOICE  } ;
           ITEMVALUES { cValToStr( oBrw:Amount:Value ) ,;
                        cValToStr( oBrw:TaxRate:Value ) ,;
                        cValToStr( oBrw:Tax:Value ) ,;
                        cValToStr( oBrw:Total:Value )  }


   oVRD:End()


return nil

//----------------------------------------------------------------------------//

function FW_RowSetToArray( oRs, cItemFlds )

   local aItems := {}

   oRs:GoTop()
   while ! oRs:Eof()
      AAdd( aItems,;
          { oRs:INVNUM, oRs:SERIAL, oRs:ITEMCODE, oRs:ITEMNAME, oRs:QUANTITY,;
            oRs:UNIT, oRs:PRICE, oRs:DISCOUNT, oRs:ID } )
      oRs:Skip()
   end
   

return aItems   

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: Unicode GET cannot be highlighted
Posted: Thu Nov 27, 2025 03:06 PM

FWH samples yunus.prg working with MariaDb :D

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: Unicode GET cannot be highlighted
Posted: Thu Nov 27, 2025 06:14 PM

Regarding your unicode GET question here you have a fine working example with FWH 25.09:

#include "FiveWin.ch"

function Main()

local oDlg, cVar := "中国版 (China)"

FW_SetUnicode( .T. )

DEFINE DIALOG oDlg 

@ 2, 2 GET cVar 

ACTIVATE DIALOG oDlg CENTERED 

return nil
regards, saludos

Antonio Linares
www.fivetechsoft.com

Continue the discussion