Anyone,
Working with amounts needs to be simple and to be displayed with 2 decimals only. I have problems displaying some numbers example with 0.09 which shows as 9.0e-002 on a workspace. If you try it in the PersonalAccount example, say as a new initial balance it does the same (ie type 0.09 as an amount and it shows as 9.0e-002). I've tried using cents only but when it comes to showing 9 cents to the user the same problem arises (eg when divide by 100). Do I need to start putting cents into strings and padding with zeros and a decimal point before displaying or printing? This would imply creating a new class for amounts which I would have expected to already be in the standard image. Is there any easy way? Thanks for any help. Theo Pronk |
Theo,
> Is there any easy way? Depends on what you mean by easy :-) You could store your values using the ScaledDecimal class which remembers the number of significant decimal places. You will have to strip the terminating 's' off when you display it as a currency value though. s := ScaledDecimal newFromNumber: 0.09 scale: 2. s printString ==> '0.09s' Alternatively you could also add a method that always displays numeric values with two decimal places. Probably best added as a method in Number Number>>currencyPrintString | stream | stream := String writeStream. self asFloat printOn: stream decimalPlaces: 2. ^stream contents 0.09 currencyPrintString ==> '0.09' Steve Zara created and made available an add-on Currency class but I can't locate the URL now. Anyone know it? Lastly, I've got a goodie available for Dolphin 4 and 5 that provides a CurrencyToText converter. You can do things like CurrencyToText new currencySymbol: $£; commas: true; integerLength: 10; fractionLength: 2; zeroFillInteger: true; convertFromLeftToRight: 12345.67890 ==> '£0,000,012,345.68' and for your example CurrencyToText new currencySymbol: $£; fractionLength: 2; convertFromLeftToRight: 0.09 ==> '£0.09' You can download it from my (new) web site http://www.idb.me.uk If you have problems with that address try the old one at http://www.iandb.org.uk (aside) I would appreciate it if you (or anyone else who would care to try it - pretty please) can let me know if you can or can't get through to the first address. I'm migrating my website across to that address but it's not proving as easy as I thought. Please tick one (a) You got redirected to the old home page (recognisable by only having one image at the top of the home page) (b) You got a default "Cobalt" server page (c) You got through. Regards Ian |
> Steve Zara created and made available an add-on Currency class but I can't
> locate the URL now. Anyone know it? Found it ... http://www.serf.org/steve/Dolphin/ |
In reply to this post by Theo Pronk
Theo,
> Working with amounts needs to be simple and to be displayed with 2 > decimals only. > > I have problems displaying some numbers example with 0.09 which shows as > 9.0e-002 on a workspace. > > If you try it in the PersonalAccount example, say as a new initial > balance it does the same (ie type 0.09 as an amount and it shows as > 9.0e-002). > > I've tried using cents only but when it comes to showing 9 cents to the > user the same problem arises (eg when divide by 100). > > Do I need to start putting cents into strings and padding with zeros and > a decimal point before displaying or printing? This would imply creating > a new class for amounts which I would have expected to already be in the > standard image. > > Is there any easy way? First of all read the comment in Float>>printOn:. The simplest change (although not really correct) you could make would be to just change this to use #printOn:decimalPlaces: passing 2 as the number of places required. This is obviously a bit of a sledgehammer approach since it changes the display for all floats in the system regardless of whether they are currency or not. If I were you, I'd revert out this change and continue as below. A better approach is to realize that all display of numbers inside text fields in the MVP framework is run through sub-instances of TypeConverter. In particular an instance of NumberToText will be being used and the conversion from a number to text is made with the (confusingly named) #leftToRight: method. You'll see that NumberToText>>leftToRight: just uses #displayString hence it picks up the default formatting. Create a subclass of NumberToText called, say, CurrencyToText and override the #leftToRight: method as: leftToRight: aNumber | stream | stream := String writeStream. aNumber printOn: stream decimalPlaces: 2. ^stream contents. Now use the ViewComposer edit any views that you have that need to use a currency display (try PersonalMoney first). Select each of text fields in turn and double click the #typeconverter aspect. This should pop up a choice dialog where you can choose your newly created CurrencyToText converter. You should then find the display of numbers more acceptable from a currency point of view. Best Regards, Andy Bower Dolphin Support http://www.object-arts.com --- Are you trying too hard? http://www.object-arts.com/Relax.htm --- |
Hi Andy and Ian,
I've actually built a new class and some loose method to deal with Money (my class definition lent from SQL server). There is still quite a lot of tweaking to do, eg allow varying presentation $999,999.99 or allowing a comma instead of a decimal point for decimal (like $999.999,99 as used in Holland). Also dealing with user input errors needs work, I don't like the idea of a wallback in a live application. Thanks to: Steve Zara for confirming my approach, perhaps Money could be a standard class in the future? The code so far see attached Money.pac Theo ====================================== Andy Bower wrote: > Theo, > > >>Working with amounts needs to be simple and to be displayed with 2 >>decimals only. >> >>I have problems displaying some numbers example with 0.09 which shows as >>9.0e-002 on a workspace. >> >>If you try it in the PersonalAccount example, say as a new initial >>balance it does the same (ie type 0.09 as an amount and it shows as >>9.0e-002). >> >>I've tried using cents only but when it comes to showing 9 cents to the >>user the same problem arises (eg when divide by 100). >> >>Do I need to start putting cents into strings and padding with zeros and >>a decimal point before displaying or printing? This would imply creating >>a new class for amounts which I would have expected to already be in the >>standard image. >> >>Is there any easy way? >> > > First of all read the comment in Float>>printOn:. The simplest change > (although not really correct) you could make would be to just change this to > use #printOn:decimalPlaces: passing 2 as the number of places required. This > is obviously a bit of a sledgehammer approach since it changes the display > for all floats in the system regardless of whether they are currency or not. > If I were you, I'd revert out this change and continue as below. > > A better approach is to realize that all display of numbers inside text > fields in the MVP framework is run through sub-instances of TypeConverter. > In particular an instance of NumberToText will be being used and the > conversion from a number to text is made with the (confusingly named) > #leftToRight: method. You'll see that NumberToText>>leftToRight: just uses > #displayString hence it picks up the default formatting. > > Create a subclass of NumberToText called, say, CurrencyToText and override > the #leftToRight: method as: > > leftToRight: aNumber > | stream | > stream := String writeStream. > aNumber printOn: stream decimalPlaces: 2. > ^stream contents. > > Now use the ViewComposer edit any views that you have that need to use a > currency display (try PersonalMoney first). Select each of text fields in > turn and double click the #typeconverter aspect. This should pop up a choice > dialog where you can choose your newly created CurrencyToText converter. You > should then find the display of numbers more acceptable from a currency > point of view. > > Best Regards, > > Andy Bower > Dolphin Support > http://www.object-arts.com > --- > Are you trying too hard? > http://www.object-arts.com/Relax.htm > --- > > > | package | package := Package name: 'Money'. package paxVersion: 0; basicComment: 'General purpose money class'. package classNames add: #Money; add: #MoneyPresenter; add: #MoneyToText; yourself. package methodNames add: #Number -> #asMoney; add: #SequenceableCollection -> #splitBeforeAndAfter:; add: #String -> #numericSeparateWithCommas; yourself. package binaryGlobalNames: (Set new yourself). package globalAliases: (Set new yourself). package allResourceNames: (Set new add: #MoneyPresenter -> 'Default view'; yourself). package setPrerequisites: (IdentitySet new add: '..\..\Object Arts\Dolphin\Base\Dolphin'; add: '..\..\Object Arts\Dolphin\MVP\Base\Dolphin MVP Base'; add: '..\..\Object Arts\Dolphin\MVP\Type Converters\Dolphin Type Converters'; yourself). package! "Class Definitions"! ScaledDecimal subclass: #Money instanceVariableNames: 'currencySymbol' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: ''! ValuePresenter subclass: #MoneyPresenter instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: ''! NumberToText subclass: #MoneyToText instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: ''! "Global Aliases"! "Loose Methods"! !Number methodsFor! asMoney "Return as an Amount of money instance." ^Money newFromNumber: self scale: 2 ! ! !Number categoriesFor: #asMoney!public! ! !SequenceableCollection methodsFor! splitBeforeAndAfter: element "Return a two element array of the collections before and after the element." | index | index := self indexOf: element. ^Array with: (self copyFrom: 1 to: index - 1) with: (self copyFrom: index + 1)! ! !SequenceableCollection categoriesFor: #splitBeforeAndAfter:!public! ! !String methodsFor! numericSeparateWithCommas "Return a string with groups of 3 digits separated by commas from the right hand side." | string result group | string := self reverse. result := String new. [string size > 3] whileTrue: [ group := string copyFrom: 1 to: 3. string := string copyFrom: 4. result := result, group, ',' ]. string size > 0 ifTrue: [ result := result, string ] ifFalse: [ result := result copyFrom: 1 to: result size - 1 ]. ^result reverse! ! !String categoriesFor: #numericSeparateWithCommas!public! ! "End of package definition"! "Source Globals"! "Classes"! Money guid: (GUID fromString: '{8FF4AD7A-9A93-441C-9104-EDB629BBA700}')! Money comment: ''! !Money categoriesForClass!Magnitude-Numbers! ! !Money methodsFor! currencyCharacter ^(self currencySymbol asString) first ! currencySymbol currencySymbol isNil ifTrue: [currencySymbol:= Locale default currency]. ^currencySymbol ! currencySymbol: anObject currencySymbol:= anObject ! displayOn: target "Append, to the <puttableStream>, target, a String whose chararacters are a representation of the receiver as a user would want to see it." | stream string split wholePart fractionPart signPrefix | stream:= ReadWriteStream on: String new. super displayOn: stream. string:= stream contents. split:= string splitBeforeAndAfter: $.. wholePart := split first. fractionPart := split last. wholePart first = $- ifTrue: [ signPrefix:= '-'. wholePart:= wholePart copyFrom: 2] ifFalse: [ signPrefix := '']. target nextPutAll: signPrefix, self currencySymbol, wholePart numericSeparateWithCommas, '.', fractionPart ! fromString: aString "Parse the string and return a <Money> instance. Return nil if a problem." | parseString sign decimals| parseString:= aString. "Check for a sign" sign:= 1. parseString first == $- ifTrue: [ sign := -1. parseString:= parseString copyFrom: 2 ]. "Remove an initial currency symbol" parseString first = self currencyCharacter ifTrue: [parseString := parseString copyFrom: 2]. "Remove commas" parseString := parseString select: [:elem| elem ~~ $,]. "Only digits and decimal point" " parseString := parseString select: [:elem| elem between: $0 and: $9 || elem = $. ]." "Check for a max 2 decimals" (parseString includes: $.) ifTrue: [ decimals:= parseString size - (parseString indexOf: $. ). (decimals > 2) ifTrue: [parseString:= parseString copyFrom: 1 to: parseString size - (decimals - 2) ] ] ifFalse: [parseString:= parseString , '.0' ]. ^Money new: parseString asNumber! printOn: target "Append, to the <puttableStream>, target, a string whose characters are a the same as those which would result from sending a #printString message to the receiver." self displayOn: target. " target nextPut: $s - as in ScalesDecimal but this line removed " ! ! !Money categoriesFor: #currencyCharacter!public! ! !Money categoriesFor: #currencySymbol!public! ! !Money categoriesFor: #currencySymbol:!public! ! !Money categoriesFor: #displayOn:!public! ! !Money categoriesFor: #fromString:!public! ! !Money categoriesFor: #printOn:!public! ! !Money class methodsFor! fromString: aString "Parse the string and return a <Currency> instance. Return nil if a problem." ^self zero fromString: aString ! new "Answer a new instance of me ( eg x= Money new (0.00) )" ^self new: 0.00 ! new: aNumber "Answer a new instance of me ( eg x= Money newFrom: 0.09 )" ^self basicNew setFraction: aNumber asFraction scale: 2; yourself ! ! !Money class categoriesFor: #fromString:!public! ! !Money class categoriesFor: #new!public! ! !Money class categoriesFor: #new:!public! ! MoneyPresenter guid: (GUID fromString: '{90E75E00-DD93-11D4-9567-D258DE47A324}')! MoneyPresenter comment: ''! !MoneyPresenter categoriesForClass!Unclassified! ! !MoneyPresenter class methodsFor! defaultModel "Answer a default model to be assigned to the receiver when it is initialized." ^0.00 asMoney ! ! !MoneyPresenter class categoriesFor: #defaultModel!public! ! MoneyToText guid: (GUID fromString: '{8BA0AF6C-C0B8-4723-8EB7-8BE6B8E00670}')! MoneyToText comment: ''! !MoneyToText categoriesForClass!MVP-Type Converters-Text! ! !MoneyToText methodsFor! leftToRight: amount "Answers the result of converting amount (of money) to a String" ^amount displayString. ! rightToLeft: aString "Answers the result of converting to a String to amount (of money)" ^Money fromString: aString ! ! !MoneyToText categoriesFor: #leftToRight:!public! ! !MoneyToText categoriesFor: #rightToLeft:!public! ! "Binary Globals"! "Resources"! (ResourceIdentifier class: MoneyPresenter name: 'Default view') assign: (Object fromBinaryStoreBytes: (ByteArray fromHexString: '2153544220312046020C0001000000566965775265736F75726365000000000E0124005354425265736F757263655354424279746541727261794163636573736F7250726F7879000000007200000062020000215354422031204E080C000A0000005354425669657750726F7879000000009A000000000000005200000010000000446F6C7068696E204D565020426173655200000008000000546578744564697462000000100000000000000000000000620000000200000082000000040000000000014401040000A001000000000000000000000000000007000000000000000000000000000000A00100000000000082000000080000006E3835800000000006030B004D6F6E6579546F5465787400000000000000005200000000000000000000000100000006010F004D65737361676553657175656E636500000000CA00000000000000D0000000620000000300000006030B004D65737361676553656E6400000000BA00000000000000520000001000000063726561746541743A657874656E743A620000000200000006020500506F696E74000000000B0000000B000000E202000000000000210100003F000000A00100009202000000000000BA00000000000000520000000F00000073656C656374696F6E52616E67653A620000000100000006030800496E74657276616C00000000030000000100000003000000A00100009202000000000000BA00000000000000520000000F0000006973546578744D6F6469666965643A620000000100000020000000A001000006010F0057494E444F57504C4143454D454E5400000000720000002C0000002C0000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05000000050000009500000024000000CA00000000000000D00000006200000000000000E202000000000000F1000000F10000000000000013000000460504000300000049636F6E0000000000000000100000000E02110053544253696E676C65746F6E50726F7879000000009A000000000000005200000007000000446F6C7068696E5200000018000000496D61676552656C617469766546696C654C6F6361746F72BA00000000000000520000000700000063757272656E74520000000C00000054657874456469742E69636F0E021F0053544245787465726E616C5265736F757263654C69627261727950726F7879000000005200000010000000646F6C7068696E64723030352E646C6C00000000'))! |
Free forum by Nabble | Edit this page |